{"record":{"id":"fe27248a73177bb1","repo":"dotnet/efcore","slug":"entitytype-is-mapped-to-the-database-function","errorCode":null,"errorMessage":"'{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.","messagePattern":"'(.+?)' is mapped to the database function '(.+?)' while '(.+?)' is mapped to the database function '(.+?)'\\. Map all the entity types in the hierarchy to the same database function\\. See https://go\\.microsoft\\.com/fwlink/\\?linkid=2130430 for more information\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs","lineNumber":2340,"sourceCode":"                }\n\n                continue;\n            }\n\n            switch (storeObjectType)\n            {\n                case StoreObjectType.Table:\n                    throw new InvalidOperationException(\n                        RelationalStrings.TphTableMismatch(\n                            entityType.DisplayName(), entityId.Value.DisplayName(),\n                            rootEntityType.DisplayName(), rootId?.DisplayName()));\n                case StoreObjectType.View:\n                    throw new InvalidOperationException(\n                        RelationalStrings.TphViewMismatch(\n                            entityType.DisplayName(), entityId.Value.DisplayName(),\n                            rootEntityType.DisplayName(), rootId?.DisplayName()));\n                case StoreObjectType.Function:\n                    throw new InvalidOperationException(\n                        RelationalStrings.TphDbFunctionMismatch(\n                            entityType.DisplayName(), entityId.Value.DisplayName(),\n                            rootEntityType.DisplayName(), rootId?.DisplayName()));\n                case StoreObjectType.InsertStoredProcedure:\n                case StoreObjectType.DeleteStoredProcedure:\n                case StoreObjectType.UpdateStoredProcedure:\n                    throw new InvalidOperationException(\n                        RelationalStrings.TphStoredProcedureMismatch(\n                            entityType.DisplayName(), entityId.Value.DisplayName(),\n                            rootEntityType.DisplayName(), rootId?.DisplayName()));\n            }\n        }\n    }\n\n    /// <inheritdoc />\n    protected override bool IsRedundant(IForeignKey foreignKey)\n        => base.IsRedundant(foreignKey)\n            && !foreignKey.DeclaringEntityType.GetMappingFragments().Any();","sourceCodeStart":2322,"sourceCodeEnd":2358,"githubUrl":"https://github.com/dotnet/efcore/blob/dbf9771522148d61a2467854921bd5dc6f6e6916/src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs#L2322-L2358","documentation":"ValidateTphMapping for StoreObjectType.Function: a TPH hierarchy mapped to a database function must keep all types on the same function. If a derived type resolves to a different function StoreObjectIdentifier than the root, EF throws because it cannot unify query roots across functions.","triggerScenarios":"Root has a discriminator (TPH) and is mapped via .ToFunction(\"fn_Base\"), and a derived type is mapped via .ToFunction(\"fn_Derived\") (or otherwise resolves to a different function), so entityId != rootId.","commonSituations":"Query-only TPH models backed by TVFs where a derived type was separately mapped; scaffolding functions then adding a discriminator.","solutions":["Remove the per-derived .ToFunction so all types share the root function.","Switch away from TPH (drop the discriminator) if each type genuinely needs its own function (TPT-style).","Map the derived type to the SAME function name/schema as the root."],"exampleFix":"// before\nmodelBuilder.Entity<Base>().HasDiscriminator(b => b.Kind).ToFunction(\"fn_Base\");\nmodelBuilder.Entity<Derived>().ToFunction(\"fn_Derived\");\n\n// after\nmodelBuilder.Entity<Base>().HasDiscriminator(b => b.Kind).ToFunction(\"fn_Base\");\n// derived omitted, inherits root function","handlingStrategy":"validation","validationCode":"bool TphAllTypesSameFunction(DbContext context)\n{\n    foreach (var root in context.Model.GetEntityTypes()\n        .Where(e => e.BaseType == null && e.FindDiscriminatorProperty() != null && e.GetDerivedTypes().Any()))\n    {\n        var rootFn = StoreObjectIdentifier.Create(root, StoreObjectType.Function);\n        if (rootFn is null) continue;\n        foreach (var d in root.GetDerivedTypes())\n            if (StoreObjectIdentifier.Create(d, StoreObjectType.Function) is { } df && df != rootFn) return false;\n    }\n    return true;\n}","typeGuard":null,"tryCatchPattern":"try { _ = context.Model; }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"database function\", StringComparison.Ordinal) && ex.Message.Contains(\"same database function\", StringComparison.Ordinal))\n{\n    throw new InvalidOperationException(\"A TPH hierarchy must map all types to one database function. Remove the derived .ToFunction or drop the discriminator.\", ex);\n}","preventionTips":["In TPH, map only the root to a function.","Switch to TPT/TPC if per-type functions are required.","Validate the built model in tests."],"tags":["ef-core","model-validation","tph","db-functions","inheritance","relational"],"analyzedSha":"dbf9771522148d61a2467854921bd5dc6f6e6916","analyzedAt":"2026-08-06T20:46:03.226Z","schemaVersion":2},"datasetVersion":"2026-08-07T02:17:10.218Z"}