dotnet/efcore · error · InvalidOperationException

' ' is mapped to the database function ' ' while ' ' is…

Error message

'{entityType}' is mapped to the database function '{function}' while '{otherEntityType}' is mapped to the database function '{otherFunction}'. Map all the entity types in the hierarchy to the same database function. 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 Function StoreObjectIdentifier than the root. TPH requires the whole hierarchy to share the same database function mapping; a derived type mapped to another function breaks the invariant.

Solutions

  1. Map the derived type to the same function as the root.
  2. Switch the hierarchy to TPT/TPC if separate functions per type are intended.
  3. Remove the extra function mapping on the derived type.

Example fix

// before
modelBuilder.Entity<Person>().ToFunction("fn_People");
modelBuilder.Entity<Customer>().ToFunction("fn_Customers"); // throws 434

// after (shared function under TPH)
modelBuilder.Entity<Person>().ToFunction("fn_People");
// derived Customer inherits fn_People
// or switch to TPT for separate functions
Defensive patterns

Strategy: validation

Validate before calling

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

Prevention

When it happens

Trigger: A TPH hierarchy where the root and a derived type map to different DB functions (e.g. via ToFunction or DbFunction mappings resolving to different StoreObjectIdentifiers).

Common situations: Configuring per-type DbFunction/ToFunction mappings while remaining on TPH; refactor that split function mappings across the hierarchy.

Related errors


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

Appendix: source

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

                }

                continue;
            }

            switch (storeObjectType)
            {
                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();

View on GitHub (pinned to 3a2006ef56)