Inheritance and Entity Framework Core: Table Per Hierarchy

Inheritance is a relationship that can be present in our models. The question is, if these models are going to be persisted in our database, how will they be represented at the level of the database? The strategy that we are going to see is known as Table per hierarchy.

The table per hierarchy strategy means that the inheritance relationship in our models will be represented in a table in our database.

Let’s see an example. Let’s suppose that we have two categories of students, those with scholarships and those without scholarships, in addition, at the software level, we have differences in the processing of these students, so we decided to separate them into two models. Since these models share implementations, we decided to have a base class, Student, and two derived classes: ScholarshipStudent and NonScholarshipStudent.

public class Student


    public int Id { get; set; }

    public string Name { get; set; }

    // ... Other properties


public class ScholarshipStudent: Student


    public string ScholarshipInstitution { get; set; }


public class NonScholarshipStudent: Student



Now, in the Data Context we put:

public DbSet Students { get; set; }

public DbSet ScholarshipStudents { get; set; }

public DbSet NonScholarshipStudents { get; set; }

After doing the above, when you add the migration, you will see the following code in the generated class:


                name: "Discriminator",

                table: "Students",

                nullable: false,

                defaultValue: "");

This column does not exist in any of my models, however, EF Core will use it to differentiate one type of student from another. By default the value of this column can be Student, ScholarshipStudent, NonScholarshipStudent, or an empty string.

The value of Discriminator will be Student when you insert a Student in the database, the value will be ScholarshipStudent when you insert an instance of ScholarshipStudent, etc. The value of Discriminator is going to be an empty string in case there are already records in the Students table before you establish the inheritance relation.

Note: In case you had records before the creation of the inheritance relationship, you should go to the database and modify the value of the Discriminator column to an appropriate one, otherwise, these records will not come out in your queries

If you look at the classes we created, ScholarshipStudent has a property, and NonScholarshipStudent does not. The idea is that within each model we can define columns that will be added to the corresponding table, but whose value will only be present for that model. In NonScholarshipStudent we do not need any property.

To make queries to the Students table, we have the following 3 options:

// Brings all kinds of students, both with and without scholarships 

var allStudents = context.Students.ToList();

// Brings only students with scholarship 

var scholarshipStudents = context.Students.OfType().ToList();

// Brings only students without scholarship 

var nonScholarshipStudents = context.Students.OfType().ToList();

As we can see, we can use the OfType function to define the type of entity we want, either scholarship or non-scholarship students.

At the moment we see that the Discriminator value is typically a String, but this does not have to be the case. We can define the value that we want EF Core to place in that column in case of the type of student we are creating. In addition, we have the option to configure the name of the Discriminator column. For that, we must make the following configuration using the Fluent API, in the OnModelCreating method of the Data Context, write:






In this way, the column that serves as a discriminator will be called StudentType, and Student, ScholarshipStudent and NonScholarshipStudent values become 1, 2 and 3, respectively.


  • Entity Framework Core makes it easy for us to model in the database our inheritance relationships that we have in C # code.
  • What EF Core does is to add a discriminator column to differentiate the type of record
  • We can customize the discriminator value using the Fluent API


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s