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

  1. Remove the UseTphMappingStrategy()/UseTptMappingStrategy()/UseTpcMappingStrategy() call from the derived entity type.
  2. Apply the strategy only on the root entity type of the hierarchy.
  3. 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

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


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)