dotnet/efcore · error · InvalidOperationException

' ' is mapped to the stored procedure ' ' while ' ' is…

Error message

'{entityType}' is mapped to the stored procedure '{sproc}' while '{otherEntityType}' is mapped to the stored procedure '{otherSproc}'. Map all the entity types in the hierarchy to the same stored procedure, or remove the discriminator and map them all to different stored procedures. See https://go.microsoft.com/fwlink/?linkid=2130430 for more information.

What it means

Thrown inside ValidateTphMapping when a derived type resolves to a different Insert/Delete/Update stored procedure StoreObjectIdentifier than the root. TPH requires the whole hierarchy to use the same stored procedure (defined on the root), so a derived type mapped to a different sproc is rejected.

Solutions

  1. Configure the stored procedure only on the root and include all derived-type parameters there.
  2. Switch the hierarchy to TPT/TPC if separate stored procedures per type are genuinely needed.

Example fix

// before (TPH, different sproc on derived)
modelBuilder.Entity<Person>().UpdateUsingStoredProcedure("sp_UpdatePerson");
modelBuilder.Entity<Customer>().UpdateUsingStoredProcedure("sp_UpdateCustomer"); // throws 435

// after (single sproc on root)
modelBuilder.Entity<Person>().UpdateUsingStoredProcedure("sp_UpdatePerson")
    .HasParameter("ShippingAddress", p => ((Customer)p).ShippingAddress);
Defensive patterns

Strategy: validation

Validate before calling

foreach (var root in modelBuilder.Model.GetEntityTypes().Where(t => t.BaseType == null))
{
    if (root.FindDiscriminatorProperty() == null) continue;
    foreach (var sot in new[] { StoreObjectType.InsertStoredProcedure, StoreObjectType.DeleteStoredProcedure, StoreObjectType.UpdateStoredProcedure })
    {
        var rootSo = StoreObjectIdentifier.Create(root, sot);
        if (rootSo == null) continue;
        foreach (var et in root.GetDerivedTypes())
        {
            var so = StoreObjectIdentifier.Create(et, sot);
            if (so != null && so.Value != rootSo.Value)
                throw new InvalidOperationException($"{et.DisplayName()} {sot} {so.Value.DisplayName()} differs from root {rootSo.Value.DisplayName()} (TPH).");
        }
    }
}

Prevention

When it happens

Trigger: A TPH hierarchy where the root declares a *UsingStoredProcedure and a derived type resolves to a different stored procedure (different name/store object) rather than reusing the root's.

Common situations: Per-type stored procedure config accidentally applied to a derived type in TPH; partial TPT migration; copy-paste of sproc config across the hierarchy.

Related errors


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

Appendix: source

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

                case StoreObjectType.Table:
                    throw new InvalidOperationException(
                        RelationalStrings.TphTableMismatch(
                            entityType.DisplayName(), entityId.Value.DisplayName(),
                            rootEntityType.DisplayName(), rootId?.DisplayName()));
                case StoreObjectType.View:
                    throw new InvalidOperationException(
                        RelationalStrings.TphViewMismatch(
                            entityType.DisplayName(), entityId.Value.DisplayName(),
                            rootEntityType.DisplayName(), rootId?.DisplayName()));
                case StoreObjectType.Function:
                    throw new InvalidOperationException(
                        RelationalStrings.TphDbFunctionMismatch(
                            entityType.DisplayName(), entityId.Value.DisplayName(),
                            rootEntityType.DisplayName(), rootId?.DisplayName()));
                case StoreObjectType.InsertStoredProcedure:
                case StoreObjectType.DeleteStoredProcedure:
                case StoreObjectType.UpdateStoredProcedure:
                    throw new InvalidOperationException(
                        RelationalStrings.TphStoredProcedureMismatch(
                            entityType.DisplayName(), entityId.Value.DisplayName(),
                            rootEntityType.DisplayName(), rootId?.DisplayName()));
            }
        }
    }

    /// <inheritdoc />
    protected override bool IsRedundant(IForeignKey foreignKey)
        => base.IsRedundant(foreignKey)
            && !foreignKey.DeclaringEntityType.GetMappingFragments().Any();

    /// <summary>
    ///     Validates the mapping fragments for an entity type.
    /// </summary>
    /// <param name="entityType">The entity type to validate.</param>
    /// <param name="logger">The logger to use.</param>
    protected virtual void ValidateMappingFragment(

View on GitHub (pinned to 3a2006ef56)