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

  1. Remove the strategy call from the derived entity; set the strategy once on the root type.
  2. Ensure any strategy-implicating calls (ToTable per derived type for TPT) are applied consistently from the root via modelBuilder.Entity<Root>().UseTptMappingStrategy().
  3. 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

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


AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06). Data as JSON: /api/errors/7213f48adfb20a7d. Report an issue: GitHub.