dotnet/efcore · error · InvalidOperationException

The entity type ' ' was configured to use some stored…

Error message

The entity type '{entityType}' was configured to use some stored procedures and is not mapped to any table. An entity type that isn't mapped to a table must be mapped to insert, update and delete stored procedures.

What it means

Thrown at the end of ValidateStoredProcedures when at least one CUD stored procedure is configured on the entity (sprocCount > 0) but entityType.GetTableName() is null (RelationalModelValidator.cs:504-510). EF requires that an entity using stored procedures be table-mapped; partial stored-procedure-only mapping is not supported (the TODO at line 505 references issue #28703).

Solutions

  1. Map the entity to a table: .ToTable("TableName") (or remove .ToView/.ToSqlQuery/null-table overrides).
  2. Provide all three CUD stored procedures if you intend full sproc mapping (the TODO notes partial isn't yet supported — though current code only requires a table name).
  3. Remove the stored-procedure configuration entirely (InsertUsingStoredProcedure / UpdateUsingStoredProcedure / DeleteUsingStoredProcedure) if the entity is read-only or view-backed.

Example fix

// before
modelBuilder.Entity<AuditLog>()
    .ToView("vw_AuditLogs")
    .InsertUsingStoredProcedure("sp_AuditLogInsert", sp => { /* ... */ });

// after — choose one path
// Option A: keep sproc, map to table
modelBuilder.Entity<AuditLog>()
    .ToTable("AuditLogs")
    .InsertUsingStoredProcedure("sp_AuditLogInsert", sp => { /* ... */ })
    .UpdateUsingStoredProcedure("sp_AuditLogUpdate", sp => { /* ... */ })
    .DeleteUsingStoredProcedure("sp_AuditLogDelete", sp => { /* ... */ });
// Option B: read-only, no sprocs
modelBuilder.Entity<AuditLog>().ToView("vw_AuditLogs").HasNoKey(); // or ToSqlQuery
Defensive patterns

Strategy: validation

Validate before calling

foreach (var et in modelBuilder.Model.GetEntityTypes())
{
    int n = (et.GetInsertStoredProcedure() is null ? 0 : 1)
          + (et.GetUpdateStoredProcedure() is null ? 0 : 1)
          + (et.GetDeleteStoredProcedure() is null ? 0 : 1);
    if (n > 0 && et.GetTableName() is null)
        throw new InvalidOperationException($"Entity '{et.Name}' has {n} sproc(s) but no table mapping; map to a table or remove all sproc config.");
}

Try / catch

try { _ = ctx.Model; }
catch (InvalidOperationException ex) when (ex.Message.Contains("not mapped to any table"))
{
    logger.LogError("Sproc-mapped entity must be table-mapped. {Msg}", ex.Message);
    throw;
}

Prevention

When it happens

Trigger: Configuring only one or two of insert/update/delete sprocs (e.g., only Insert) and removing the table mapping. Or calling .ToTable((string)null) / .ToView("X") while still setting .InsertUsingStoredProcedure(...). The validator counts configured sprocs and demands a table name when any exist.

Common situations: Switching an entity to a view (ToView) but leaving CUD sproc config from a previous iteration; migrating from ToTable to ToSqlQuery without removing sproc configuration; partial scaffolding that registered insert sproc only.

Related errors


AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11). Data as JSON: /api/errors/c4207d6f083ff6d6. Report an issue: GitHub.

Appendix: source

Thrown at src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs:509

            ValidateStoredProcedureName(StoreObjectType.InsertStoredProcedure, entityType);
            ValidateSproc(insertStoredProcedure, mappingStrategy, logger);
            sprocCount++;
        }

        var updateStoredProcedure = entityType.GetUpdateStoredProcedure();
        if (updateStoredProcedure != null)
        {
            ValidateStoredProcedureName(StoreObjectType.UpdateStoredProcedure, entityType);
            ValidateSproc(updateStoredProcedure, mappingStrategy, logger);
            sprocCount++;
        }

        if (sprocCount > 0
            // TODO: Support this with #28703
            //&& sprocCount < 3
            && entityType.GetTableName() == null)
        {
            throw new InvalidOperationException(RelationalStrings.StoredProcedureUnmapped(entityType.DisplayName()));
        }

        static void ValidateStoredProcedureName(
            StoreObjectType storedProcedureType,
            IEntityType entityType)
        {
            var sprocId = StoreObjectIdentifier.Create(entityType, storedProcedureType);
            if (sprocId == null)
            {
                throw new InvalidOperationException(
                    RelationalStrings.StoredProcedureNoName(
                        entityType.DisplayName(), storedProcedureType));
            }
        }
    }

    /// <summary>
    ///     Validates a single stored procedure and all entity types mapped to it.

View on GitHub (pinned to 3a2006ef56)