{"record":{"id":"66a086a5a5d7cff7","repo":"dotnet/efcore","slug":"entitytype-is-mapped-to-the-stored-procedure","errorCode":null,"errorMessage":"'{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.","messagePattern":"'(.+?)' is mapped to the stored procedure '(.+?)' while '(.+?)' is mapped to the stored procedure '(.+?)'\\. 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\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs","lineNumber":2347,"sourceCode":"                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();\n\n    /// <summary>\n    ///     Validates the mapping fragments for an entity type.\n    /// </summary>\n    /// <param name=\"entityType\">The entity type to validate.</param>\n    /// <param name=\"logger\">The logger to use.</param>\n    protected virtual void ValidateMappingFragment(","sourceCodeStart":2329,"sourceCodeEnd":2365,"githubUrl":"https://github.com/dotnet/efcore/blob/dbf9771522148d61a2467854921bd5dc6f6e6916/src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs#L2329-L2365","documentation":"ValidateTphMapping for stored procedures (Insert/Delete/Update): in a TPH hierarchy every type must use the same sproc as the root for a given operation. If a derived type resolves to a different stored-procedure StoreObjectIdentifier than the root, the model is rejected. (Distinct from StoredProcedureTphDuplicate, which fires when the derived type is on the SAME store object but declares its own sproc.)","triggerScenarios":"Root has a discriminator (TPH) and an .InsertStoredProcedure(s => s.HasName(\"sp_Base\")), and a derived type is mapped to a DIFFERENT sproc name so its StoreObjectIdentifier differs from the root's, hitting the switch default in ValidateTphMapping.","commonSituations":"TPH model where a derived type was given its own named sproc; scaffolding sprocs per type then enabling TPH without unifying names.","solutions":["Remove the derived type's .InsertStoredProcedure/.UpdateStoredProcedure/.DeleteStoredProcedure so it shares the root sproc.","Move the hierarchy to TPT/TPC if per-type sprocs are genuinely required (no discriminator).","Map the derived type to the SAME sproc name/schema as the root and define all parameters there."],"exampleFix":"// before\nmodelBuilder.Entity<Base>().HasDiscriminator(b => b.Kind)\n    .InsertStoredProcedure(s => s.HasName(\"sp_Base_Insert\"));\nmodelBuilder.Entity<Derived>().InsertStoredProcedure(s => s.HasName(\"sp_Derived_Insert\"));\n\n// after\nmodelBuilder.Entity<Base>().HasDiscriminator(b => b.Kind)\n    .InsertStoredProcedure(s => s.HasName(\"sp_Base_Insert\"));\n// derived omitted, shares root sproc","handlingStrategy":"validation","validationCode":"bool TphAllTypesSameSproc(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        foreach (var sot in new[] { StoreObjectType.InsertStoredProcedure, StoreObjectType.DeleteStoredProcedure, StoreObjectType.UpdateStoredProcedure })\n        {\n            var rootSo = StoreObjectIdentifier.Create(root, sot);\n            if (rootSo is null) continue;\n            foreach (var d in root.GetDerivedTypes())\n                if (StoreObjectIdentifier.Create(d, sot) is { } ds && ds != rootSo) return false;\n        }\n    }\n    return true;\n}","typeGuard":null,"tryCatchPattern":"try { _ = context.Model; }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"stored procedure\", StringComparison.Ordinal) && ex.Message.Contains(\"same stored procedure\", StringComparison.Ordinal))\n{\n    throw new InvalidOperationException(\"A TPH hierarchy must use one sproc per operation, declared on the root. Remove the derived sproc mapping or drop the discriminator.\", ex);\n}","preventionTips":["Configure TPH sprocs only on the root entity.","If per-type sprocs are needed, remove the discriminator and switch to TPT/TPC.","Add a test that builds the model after sproc configuration."],"tags":["ef-core","model-validation","tph","stored-procedures","inheritance","relational"],"analyzedSha":"dbf9771522148d61a2467854921bd5dc6f6e6916","analyzedAt":"2026-08-06T20:46:03.226Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}