dotnet/efcore · error · InvalidOperationException

The entity type '{entityType}' cannot be instantiated becaus

Error message

The entity type '{entityType}' cannot be instantiated because its corresponding CLR type is abstract, but the entity type was mapped to '{storeObject}' using the 'TPC' mapping strategy. Only instantiable types should be mapped. See https://go.microsoft.com/fwlink/?linkid=2130430 for more information.

What it means

Stored-procedure mapping (Insert/Update/DeleteUsingStoredProcedure) is rejected for an abstract entity type that is mapped with the TPC (Table-per-Concrete-type) strategy. In TPC each concrete leaf type gets its own table, so an abstract base can never be instantiated or have a row written via a sproc; mapping a sproc onto it is a modeling error (RelationalEntityTypeBuilderExtensions.UseSproc.cs:934, RelationalStrings.AbstractTpc).

Source

Thrown at src/EFCore.Relational/Extensions/RelationalEntityTypeBuilderExtensions.UseSproc.cs:934

        return entityTypeBuilder;
    }

    private static EntityTypeBuilder<TEntity> UseStoredProcedure<TEntity>(
        EntityTypeBuilder<TEntity> entityTypeBuilder,
        string? name,
        string? schema,
        StoreObjectType sprocType,
        Action<StoredProcedureBuilder<TEntity>> buildAction)
        where TEntity : class
    {
        Check.NotNull(buildAction);

        var entityType = entityTypeBuilder.Metadata;
        if (entityType.GetMappingStrategy() == RelationalAnnotationNames.TpcMappingStrategy
            && !entityType.ClrType.IsInstantiable())
        {
            throw new InvalidOperationException(
                RelationalStrings.AbstractTpc(entityType.DisplayName(), name ?? sprocType.ToString()));
        }

        var sprocBuilder = InternalStoredProcedureBuilder.HasStoredProcedure(
            entityType, sprocType, name, schema);
        buildAction(new StoredProcedureBuilder<TEntity>(sprocBuilder.Metadata, entityTypeBuilder));

        return entityTypeBuilder;
    }

    private static OwnedNavigationBuilder UseStoredProcedure(
        OwnedNavigationBuilder ownedNavigationBuilder,
        string? name,
        string? schema,
        StoreObjectType sprocType,
        Action<OwnedNavigationStoredProcedureBuilder> buildAction)
    {
        Check.NotNull(buildAction);

View on GitHub (pinned to dbf9771522)

Solutions

  1. Move the *UsingStoredProcedure configuration to each concrete (non-abstract) derived entity type instead of the abstract base.
  2. Guard the call: only configure the sproc when entityType.ClrType.IsInstantiable() is true.
  3. If the base must define the mapping contract, use a shared partial OnModelCreating applied per concrete type, not on the abstract root.

Example fix

// before
modelBuilder.Entity<AnimalBase>()            // AnimalBase is abstract, TPC
    .ToTable(("Animals", "dbo"))
    .UseTpcMappingStrategy()
    .InsertUsingStoredProcedure("InsertAnimal", b => { ... });

// after (configure sprocs on each concrete type)
modelBuilder.Entity<AnimalBase>().UseTpcMappingStrategy();
modelBuilder.Entity<Dog>()
    .InsertUsingStoredProcedure("InsertDog", b => { ... });
modelBuilder.Entity<Cat>()
    .InsertUsingStoredProcedure("InsertCat", b => { ... });
Defensive patterns

Strategy: validation

Validate before calling

if (typeof(TEntity).IsAbstract
    && entityType.GetMappingStrategy() == RelationalAnnotationNames.TpcMappingStrategy)
{
    throw new InvalidOperationException("Abstract TPC base cannot be sproc-mapped.");
}
// only configure sprocs for instantiable types
if (typeof(TEntity).IsInstantiable())
{
    builder.Entity<TEntity>().InsertUsingStoredProcedure(...);
}

Prevention

When it happens

Trigger: Calling InsertUsingStoredProcedure<TEntity>/UpdateUsingStoredProcedure<TEntity>/DeleteUsingStoredProcedure<TEntity> on an abstract base class TEntity whose hierarchy is configured with UseTpcMappingStrategy().

Common situations: Refactoring an existing TPH/TPT hierarchy to TPC while leaving the stored-procedure configuration on the abstract base; applying a shared configuration action to all entity types in a hierarchy without filtering out the abstract root; scaffolding/configuring sprocs generically across IEntityType instances.

Related errors


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