{"record":{"id":"7a8b9af505bfd15f","repo":"dotnet/efcore","slug":"hasdiscriminatorinjsonid-or-hasrootdiscriminato","errorCode":null,"errorMessage":"'HasDiscriminatorInJsonId' or 'HasRootDiscriminatorInJsonId' was called on a non-root entity type '{entityType}'. Discriminator configuration for the JSON 'id' property can only be made on the document root.","messagePattern":"'HasDiscriminatorInJsonId' or 'HasRootDiscriminatorInJsonId' was called on a non-root entity type '(.+?)'\\. Discriminator configuration for the JSON 'id' property can only be made on the document root\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Cosmos/Infrastructure/Internal/CosmosModelValidator.cs","lineNumber":559,"sourceCode":"\n            properties[jsonName] = navigation;\n        }\n    }\n\n    /// <summary>\n    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to\n    ///     the same compatibility standards as public APIs. It may be changed or removed without notice in\n    ///     any release. You should only use it directly in your code with extreme caution and knowing that\n    ///     doing so can result in application failures when updating to a new Entity Framework Core release.\n    /// </summary>\n    protected virtual void ValidateDiscriminatorMappings(\n        IEntityType entityType,\n        IDiagnosticsLogger<DbLoggerCategory.Model.Validation> logger)\n    {\n        if (!entityType.IsDocumentRoot()\n            && entityType.FindAnnotation(CosmosAnnotationNames.DiscriminatorInKey) != null)\n        {\n            throw new InvalidOperationException(CosmosStrings.DiscriminatorInKeyOnNonRoot(entityType.DisplayName()));\n        }\n\n        if (!entityType.IsDocumentRoot()\n            && entityType.FindAnnotation(CosmosAnnotationNames.HasShadowId) != null)\n        {\n            throw new InvalidOperationException(CosmosStrings.HasShadowIdOnNonRoot(entityType.DisplayName()));\n        }\n    }\n\n    /// <summary>\n    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to\n    ///     the same compatibility standards as public APIs. It may be changed or removed without notice in\n    ///     any release. You should only use it directly in your code with extreme caution and knowing that\n    ///     doing so can result in application failures when updating to a new Entity Framework Core release.\n    /// </summary>\n    protected override void ValidateIndex(\n        IIndex index,\n        IDiagnosticsLogger<DbLoggerCategory.Model.Validation> logger)","sourceCodeStart":541,"sourceCodeEnd":577,"githubUrl":"https://github.com/dotnet/efcore/blob/3a2006ef569de08368d59db5e1468aa8f407e4f8/src/EFCore.Cosmos/Infrastructure/Internal/CosmosModelValidator.cs#L541-L577","documentation":"Thrown when HasDiscriminatorInJsonId or HasRootDiscriminatorInJsonId is configured on a non-root entity type. Discriminator-in-JSON-id configuration controls how the discriminator value is encoded into the document 'id' field, which is a document-root concern. The validator checks for the DiscriminatorInKey annotation on any entity whose IsDocumentRoot() is false and throws.","triggerScenarios":"Calling HasDiscriminatorInJsonId() (or HasRootDiscriminatorInJsonId()) on an entity type that is part of a hierarchy but is not the document root. Fires during ValidateDiscriminatorMappings at model finalization.","commonSituations":"Applying id-discriminator configuration inside a per-derived-type config; copying a root configuration to derived types; not realizing the call is meaningful only on the root.","solutions":["Move the HasDiscriminatorInJsonId / HasRootDiscriminatorInJsonId call to the document-root entity type of the hierarchy.","If using IEntityTypeConfiguration<T>, only register this configuration for the root type.","Remove the call from derived types entirely; the root setting covers the whole hierarchy."],"exampleFix":"// before\nmodelBuilder.Entity<DerivedOrder>()   // : Order\n    .HasDiscriminatorInJsonId();\n\n// after\nmodelBuilder.Entity<Order>()           // the document root\n    .HasDiscriminatorInJsonId();","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"static bool IsDocumentRoot(Type t, IModel model)\n    => model.FindEntityType(t)?.IsDocumentRoot() ?? false;\n\nif (IsDocumentRoot(typeof(Order), modelBuilder.Model))\n    modelBuilder.Entity<Order>().HasDiscriminatorInJsonId();","tryCatchPattern":null,"preventionTips":["Call HasDiscriminatorInJsonId / HasRootDiscriminatorInJsonId only on the document root.","Use IEntityTypeConfiguration<TRoot> for id-discriminator configuration.","Add a CI test asserting no non-root type carries the DiscriminatorInKey annotation."],"tags":["cosmos","model-validation","discriminator","json-id","hierarchy","configuration"],"backgroundTag":null,"analyzedSha":"3a2006ef569de08368d59db5e1468aa8f407e4f8","analyzedAt":"2026-08-11T23:42:04.146Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}