dotnet/efcore · error · InvalidOperationException
The derived entity type
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 non-null BaseType) was explicitly configured with a mapping strategy (TPH/TPT/TPC). Mapping strategy is a hierarchy-wide setting that must be declared once on the root entity type; configuring it on a derived type is ambiguous and EF rejects it. Even if the strategy matches the base, only the root may carry the annotation.
Solutions
- Remove the UseTphMappingStrategy()/UseTptMappingStrategy()/UseTpcMappingStrategy() call from the derived entity type.
- Apply the strategy only on the root entity type of the hierarchy.
- If the root was supposed to be different, restructure the hierarchy so the configured type is actually the root.
Example fix
// before modelBuilder.Entity<Animal>().UseTpcMappingStrategy(); modelBuilder.Entity<Dog>().UseTpcMappingStrategy(); // Dog is derived -> error // after - strategy declared only on the root modelBuilder.Entity<Animal>().UseTpcMappingStrategy();
Defensive patterns
Strategy: validation
Validate before calling
// Strategy may only be set on root entity types.
foreach (var et in db.Model.GetEntityTypes())
{
var strategy = et[RelationalAnnotationNames.MappingStrategy] as string;
if (strategy != null && et.BaseType != null)
Console.WriteLine($"Derived type {et.Name} incorrectly declares strategy {strategy}");
} Type guard
static bool IsHierarchyRoot(IEntityType et) => et.BaseType == null;
Try / catch
try { _ = db.Model; } catch (InvalidOperationException ex) when (ex.Message.Contains("configured with the") && ex.Message.Contains("mapping strategy")) { // remove the strategy call from the derived entity } Prevention
- Call UseTphMappingStrategy/UseTptMappingStrategy/UseTpcMappingStrategy only on the root entity.
- During code review, flag any mapping-strategy call inside a configuration for a derived type.
- Add a startup test that builds the model for the hierarchy.
When it happens
Trigger: ValidateInheritanceMapping detects entityType.BaseType != null and a non-null mappingStrategy annotation that is either absent on the base or differs from the base's strategy; throws RelationalStrings.DerivedStrategy. Triggered by calling UseTphMappingStrategy()/UseTptMappingStrategy()/UseTpcMappingStrategy() on a derived entity.
Common situations: Copy-pasting UseTpcMappingStrategy() onto every entity in a hierarchy; refactoring a hierarchy and leaving strategy calls on the old root that became derived; scaffolding customizations that added strategy on a child.
Related errors
- The element type of the result of
- The mapping strategy
- The mapping strategy
- Both ' ' and ' ' are mapped to the table ' '. All the…
- Both ' ' and ' ' are mapped to the stored procedure ' '…
AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11).
Data as JSON: /api/errors/7213f48adfb20a7d.
Report an issue: GitHub.
Appendix: 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 3a2006ef56)