dotnet/efcore · error · InvalidOperationException
The derived entity type '{entityType}' was configured with t
Error message
The derived entity type '{entityType}' was configured with the '{strategy}' mapping strategy. Only the root entity type should be configured with a mapping strategy. See https://go.microsoft.com/fwlink/?linkid=2130430 for more information. What it means
A derived entity type (one with a BaseType) was explicitly configured with a mapping strategy (TPH/TPT/TPC) that differs from its base type's strategy. Mapping strategy must be set only on the root of the hierarchy and applies to the whole hierarchy. Thrown from ValidateInheritanceMapping when entityType.BaseType != null and the strategy differs from the base.
Source
Thrown at src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs:2090
?? entityType.GetSqlQuery()
?? entityType.GetInsertStoredProcedure()?.GetSchemaQualifiedName()
?? entityType.GetDeleteStoredProcedure()?.GetSchemaQualifiedName()
?? entityType.GetUpdateStoredProcedure()?.GetSchemaQualifiedName();
if (mappingStrategy == RelationalAnnotationNames.TpcMappingStrategy
&& !entityType.ClrType.IsInstantiable()
&& storeObjectName != null)
{
throw new InvalidOperationException(
RelationalStrings.AbstractTpc(entityType.DisplayName(), storeObjectName));
}
}
if (entityType.BaseType != null)
{
if (mappingStrategy != null
&& mappingStrategy != (string?)entityType.BaseType[RelationalAnnotationNames.MappingStrategy])
{
throw new InvalidOperationException(
RelationalStrings.DerivedStrategy(entityType.DisplayName(), mappingStrategy));
}
return;
}
// Hierarchy mapping strategy must be the same across all types of mappings (only for root types)
if (entityType.FindDiscriminatorProperty() != null)
{
if (mappingStrategy is not null
and not RelationalAnnotationNames.TphMappingStrategy)
{
throw new InvalidOperationException(
RelationalStrings.NonTphMappingStrategy(mappingStrategy, entityType.DisplayName()));
}
ValidateTphMapping(entityType, StoreObjectType.Table);
ValidateTphMapping(entityType, StoreObjectType.View);View on GitHub (pinned to dbf9771522)
Solutions
- Remove the strategy call from the derived entity; set the strategy once on the root type.
- Ensure any strategy-implicating calls (ToTable per derived type for TPT) are applied consistently from the root via modelBuilder.Entity<Root>().UseTptMappingStrategy().
- Audit OnModelCreating for stray UseXxxMappingStrategy calls on non-root entities.
Example fix
// before modelBuilder.Entity<Person>().UseTphMappingStrategy(); modelBuilder.Entity<Student>().UseTptMappingStrategy(); // error: derived // after (strategy set on root only) modelBuilder.Entity<Person>().UseTptMappingStrategy(); // Student inherits TPT from Person
Defensive patterns
Strategy: validation
Validate before calling
using (var ctx = new MyContext()) { ctx.Model.ToDebugString(); }
// Assert strategy is declared only on roots.
foreach (var et in ctx.Model.GetEntityTypes())
{
var s = (string?)et[Microsoft.EntityFrameworkCore.Metadata.RelationalAnnotationNames.MappingStrategy];
if (s != null && et.BaseType != null)
Debug.Fail($"Derived type {et.Name} declares strategy '{s}'; set it on the root only.");
} Type guard
static bool IsHierarchyRoot(Microsoft.EntityFrameworkCore.Metadata.IEntityType et) => et.BaseType == null; // Guard: only call UseXxxMappingStrategy() when IsHierarchyRoot(et) is true.
Try / catch
try { using var ctx = new MyContext(); _ = ctx.Model; }
catch (InvalidOperationException ex) when (ex.Message.Contains("mapping strategy"))
{ log.Error("Strategy set on a derived type; move it to the root: {Msg}", ex.Message); throw; } Prevention
- Set UseXxxMappingStrategy once on the root entity only.
- Search OnModelCreating for UseTph/Tpt/TpcMappingStrategy and confirm each call site targets a root type.
- Cover strategy placement in a startup model-build test.
When it happens
Trigger: Calling modelBuilder.Entity<Derived>().UseTptMappingStrategy() while the root has UseTphMappingStrategy() (or no strategy); accidentally applying [UseTpcMappingStrategy] attribute or ToTable(t) calls that imply a strategy on a derived type.
Common situations: Reading outdated docs that suggested setting strategy per type; copy-pasting root configuration to derived entities; refactoring a hierarchy and forgetting to remove strategy calls on children.
Related errors
- The mapping strategy '{mappingStrategy}' specified on '{enti
- The specified discriminator value '{value}' for '{entityType
- The mapping strategy '{mappingStrategy}' used for '{entityTy
- The short name for '{entityType1}' is '{discriminatorValue}'
- Both '{entityType}' and '{otherEntityType}' are mapped to th
AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06).
Data as JSON: /api/errors/7213f48adfb20a7d.
Report an issue: GitHub.