Understanding Inheritance in Entity Framework Core

Muhammad Abdullah
4 min readAug 30, 2023

--

Entity Framework Core (EF Core) is an open-source, lightweight, extensible, and cross-platform version of Entity Framework, which is a popular Object-Relational Mapping (ORM) framework for. NET. EF Core enables .NET developers to work with a database using .NET objects. It eliminates the need for most of the data-access code that developers usually need to write.

In this blog post, we will discuss the different types of inheritance supported by EF Core and how to implement them with simple examples.

What is Inheritance?

In object-oriented programming, inheritance is a mechanism that allows you to create a new class based on an existing class. The new class, known as a derived class or child class, inherits attributes and behavior (methods) of the existing class, known as the base class or parent class. Inheritance helps to promote the reuse of existing code and establish a relationship between the parent and child classes.

Inheritance in EF Core

In EF Core, there are three main types of inheritance:

1. Table-Per-Hierarchy (TPH)
2. Table-Per-Type (TPT)
3. Table-Per-Class (TPC)

Let’s discuss each of these in detail with examples.

1. Table-Per-Hierarchy (TPH)

- TPH is the default inheritance mapping pattern in EF Core.
- It uses a single table to store the data for all types in the hierarchy, and a discriminator column is used to identify the type of each row.
- It is the most efficient inheritance strategy in terms of query performance because only one table needs to be queried.

Example:

Consider a base class `User` and a derived class `UserExtended`.

public class User
{
public Guid UserId { get; set; }
public string Email { get; set; }
// other properties…
}
public class UserExtended : User
{
public Guid? EmployeeId { get; set; }
// other properties…
}

In TPH, both `User` and `UserExtended` will be stored in a single table, and a discriminator column will be used to identify the type of each row.

Here is how you can configure TPH using the Fluent API:

public class AppDbContext : DbContext
{
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.HasDiscriminator<string>("UserType")
.HasValue<User>("User")
.HasValue<UserExtended>("UserExtended");
}
}

In this example, there will be a single table for both `User` and `UserExtended`, with a discriminator column `UserType` to distinguish between `User` and `UserExtended` records.

2. Table-Per-Type (TPT)

- TPT uses a separate table for each type in the hierarchy. It creates a table for the base type and separate tables for each of the derived types.
- Each table contains only the properties of that type (excluding the properties of the base type).

Example:

Using the same `User` and `UserExtended` classes as above, in TPT, there will be two separate tables, one for `User` and one for `UserExtended`.

Here is how you can configure TPT using the Fluent API:

public class AppDbContext : DbContext
{
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<UserExtended>()
.ToTable("UserExtendeds");
}
}

In this example, there will be two separate tables, one for `User` and one for `UserExtended`. The `UserExtended` table will have a foreign key to the `User` table.

3. Table-Per-Class (TPC)

- TPC uses a separate table for each class (entity) but doesn’t use a database inheritance relationship.
- EF Core does not support TPC natively, so you would need to manually configure the model to behave like TPC.

Example:

Using the same `User` and `UserExtended` classes as above, in TPC, there will be two separate tables, one for `User` and one for `UserExtended`, and there will be no relationship between the two tables.

Here is how you can configure TPC using the Fluent API:

public class AppDbContext : DbContext
{
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>().ToTable("Users");
modelBuilder.Entity<UserExtended>().ToTable("UserExtendeds");
}
}

In this example, there will be two separate tables, one for `User` and one for `UserExtended`, and there will be no relationship between the two tables.

Conclusion

In this blog post, we discussed the different types of inheritance supported by EF Core and how to implement them with simple examples. TPH is the most efficient in terms of query performance, but it may not be suitable for all scenarios. TPT is more normalized and may be a better fit for complex models. TPC is not natively supported by EF Core, but it can be configured manually if needed.

Choose the inheritance strategy that best fits your application’s needs and requirements.

--

--

Muhammad Abdullah

Full Stack Developer .NET Core| JavaScript | Unity | Blockchain dApps | MongoDb | Express | Node | Angular | React | Flutter