Feb 17 2025
Sponsored
• Struggling with slow EF Core performance? Unlock up to 14x faster operations and cut execution time by 94% with high-performance library for EF Core. Seamlessly enhance your app with Bulk Insert, Update, Delete, and Merge—fully integrated into your existing EF Core workflows. Trusted by 5,000+ developers since 2014. Ready to boost your performance? Explore the solution
• With Postman’s AI Agent Builder making waves, I can’t wait to see what’s in store at POST/CON this year. Last year was phenomenal - you remember I attended it in SF. Sign up for updates now! Save the date and join the mailing list here.
Many thanks to the sponsors who make it possible for this newsletter to be free for readers. Become a sponsor.
What is a Discriminator in Entity Framework? In Entity Framework (EF) Core, a discriminator is a special column used in Table Per Hierarchy (TPH) inheritance to differentiate between multiple entity types stored in a single table. How Discriminators Work? When using inheritance in EF Core, all derived types are mapped to the same database table. To distinguish between different entity types, EF Core automatically adds a discriminator column in the table. The discriminator column stores a string or an integer value representing the type of entity. Let's see it through example.
Example: Single Table Inheritance
Imagine you have a Base Class Vehicle and two derived classes: Car and Bike.
Step 1: Define the Entities
public class Vehicle{ public int Id { get; set; } public string Model { get; set; } = string.Empty;} public class Car : Vehicle{ public int NumberOfDoors { get; set; }} public class Bike : Vehicle{ public bool HasGear { get; set; }}
Step 2: Configure EF Core in DbContext EF Core automatically adds a Discriminator column when you use TPH inheritance.
public class AppDbContext : DbContext{ public DbSet<Vehicle> Vehicles { get; set; } public DbSet<Car> Cars { get; set; } public DbSet<Bike> Bikes { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer("your_connection_string"); }}
Step 3: Migration and Database Table Run the following commands:
dotnet ef migrations add InitialCreatedotnet ef database update
Generated Table (Single Table for All Entities)
Discriminator: Determines if the row is for Car or Bike.
NULL values exist for columns that are not applicable to that entity.
By default, EF Core names the column Discriminator. However, you can customize its name and values. Example: Custom Discriminator Name and Values Modify OnModelCreating in AppDbContext:
protected override void OnModelCreating(ModelBuilder modelBuilder){ modelBuilder.Entity<Vehicle>() .HasDiscriminator<string>("VehicleType") .HasValue<Car>("CarType") .HasValue<Bike>("BikeType");}
Effect on Database Table

EF Core automatically filters data based on the discriminator. Query All Vehicles
var vehicles = context.Vehicles.ToList();
Returns all records (both Cars and Bikes).
Query Only Cars
var cars = context.Cars.ToList();
EF Core translates this into:
SELECT * FROM Vehicles WHERE VehicleType = 'CarType';
Query Only Bikes
var bikes = context.Bikes.ToList();
EF Core translates this into:
SELECT * FROM Vehicles WHERE VehicleType = 'BikeType';
Sometimes, you may want to change the discriminator dynamically. Example: Convert a Bike to a Car
var bike = context.Bikes.FirstOrDefault(b => b.Id == 2);if (bike != null){ var car = new Car { Id = bike.Id, // Keep the same ID Model = bike.Model, NumberOfDoors = 4 }; context.Bikes.Remove(bike); context.Cars.Add(car); context.SaveChanges();}
The discriminator column value changes from 'BikeType' to 'CarType'.
EF Core 8 and 9 support enums as discriminator values. Step 1: Define an Enum
public enum VehicleType{ Unknown = 0, Car = 1, Bike = 2}
Step 2: Apply Discriminator with Enum
protected override void OnModelCreating(ModelBuilder modelBuilder){ modelBuilder.Entity<Vehicle>() .HasDiscriminator<VehicleType>("VehicleType") .HasValue<Car>(VehicleType.Car) .HasValue<Bike>(VehicleType.Bike);}
Effect on Database Table:

Advantages of TPH (Discriminator-Based) Inheritance:
csharp
modelBuilder.Entity<Car>().ToTable("Cars");
modelBuilder.Entity<Bike>().ToTable("Bikes");
EF Core Discriminators enable Table Per Hierarchy (TPH) inheritance.
The discriminator column is used to differentiate entity types within a single table.
You can customize the discriminator name and values. EF Core 8 & 9 allow enum-based discriminators.
Performance considerations should guide whether to use TPH (with discriminators) or TPT..
That's all from me today.
P.S. Follow me on YouTube.
Stop arguing about code style. In this course you get a production-proven setup with analyzers, CI quality gates, and architecture tests — the exact system I use in real projects. Join here.
Not sure yet? Grab the free Starter Kit — a drop-in setup with the essentials from Module 01.
Design Patterns that Deliver — Solve real problems with 5 battle-tested patterns (Builder, Decorator, Strategy, Adapter, Mediator) using practical, real-world examples. Trusted by 650+ developers.
Just getting started? Design Patterns Simplified covers 10 essential patterns in a beginner-friendly, 30-page guide for just $9.95.
Every Monday morning, I share 1 actionable tip on C#, .NET & Architecture that you can use right away. Join here.
Join 20,000+ subscribers who mass-improve their .NET skills with actionable tips on C#, Architecture & Best Practices.
Subscribe to the TheCodeMan.net and be among the 20,000+ subscribers gaining practical tips and resources to enhance your .NET expertise.