{"record":{"id":"c6c9a303812d6911","repo":"dotnet/efcore","slug":"using-methodname-on-dbset-of-entitytype-is","errorCode":null,"errorMessage":"Using '{methodName}' on DbSet of '{entityType}' is not supported since '{entityType}' is part of hierarchy and does not contain a discriminator property.","messagePattern":"Using '(.+?)' on DbSet of '(.+?)' is not supported since '(.+?)' is part of hierarchy and does not contain a discriminator property\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Relational/Extensions/RelationalQueryableExtensions.cs","lineNumber":192,"sourceCode":"        return queryableSource.Provider.CreateQuery<TEntity>(\n            GenerateFromSqlQueryRoot(\n                queryableSource,\n                sql.Format,\n                sql.GetArguments()));\n    }\n\n    private static FromSqlQueryRootExpression GenerateFromSqlQueryRoot(\n        IQueryable source,\n        string sql,\n        object?[] arguments,\n        [CallerMemberName] string memberName = null!)\n    {\n        var entityQueryRootExpression = (EntityQueryRootExpression)source.Expression;\n\n        var entityType = entityQueryRootExpression.EntityType;\n        return (entityType.BaseType != null || entityType.GetDirectlyDerivedTypes().Any())\n            && entityType.FindDiscriminatorProperty() == null\n                ? throw new InvalidOperationException(\n                    RelationalStrings.MethodOnNonTphRootNotSupported(memberName, entityType.DisplayName()))\n                : new FromSqlQueryRootExpression(\n                    entityQueryRootExpression.QueryProvider!,\n                    entityType,\n                    sql,\n                    Expression.Constant(arguments));\n    }\n\n    #endregion\n\n    #region SplitQuery\n\n    /// <summary>\n    ///     Returns a new query which is configured to load the collections in the query results in a single database query.\n    /// </summary>\n    /// <remarks>\n    ///     <para>\n    ///         This behavior generally guarantees result consistency in the face of concurrent updates","sourceCodeStart":174,"sourceCodeEnd":210,"githubUrl":"https://github.com/dotnet/efcore/blob/3a2006ef569de08368d59db5e1468aa8f407e4f8/src/EFCore.Relational/Extensions/RelationalQueryableExtensions.cs#L174-L210","documentation":"GenerateFromSqlQueryRoot throws MethodOnNonTphRootNotSupported when FromSqlRaw/FromSqlInterpolated is called on a DbSet whose entity type participates in an inheritance hierarchy (has a base type or derived types) but has no discriminator property. FromSql can only target the TPH root that owns the discriminator so EF can filter rows; an inheritance branch without a discriminator cannot be the SQL root.","triggerScenarios":"Calling context.Set<DerivedEntity>().FromSqlRaw(...) where DerivedEntity is part of TPT/TPC inheritance, or TPH without a configured discriminator. The check is `entityType.BaseType != null || entityType.GetDirectlyDerivedTypes().Any()` combined with `FindDiscriminatorProperty() == null`.","commonSituations":"Switching from TPH to TPT/TPC and reusing existing FromSql calls; scaffolding a hierarchy without a discriminator column; forgetting HasDiscriminator on an abstract base; calling FromSql on a leaf entity in a hierarchy.","solutions":["Call FromSqlRaw on the hierarchy root DbSet and add a WHERE clause filtering by discriminator/column values.","If TPH, configure HasDiscriminator on the root entity so the check passes.","For TPT/TPC, query the root and project, or use a plain SqlQueryRaw<T> for the leaf type instead of DbSet.FromSql."],"exampleFix":"// before (DerivedEntity is in a hierarchy, no discriminator)\nvar rows = await db.Set<DerivedEntity>()\n    .FromSqlRaw(\"SELECT * FROM derived_view\").ToListAsync();\n\n// after — query the root and filter\nvar rows = await db.Set<BaseEntity>()\n    .FromSqlRaw(\"SELECT * FROM base_view WHERE Discriminator = 'DerivedEntity'\")\n    .OfType<DerivedEntity>().ToListAsync();","handlingStrategy":"validation","validationCode":"var entityType = db.Model.FindEntityType(typeof(TEntity))!;\nif ((entityType.BaseType != null || entityType.GetDirectlyDerivedTypes().Any())\n    && entityType.FindDiscriminatorProperty() == null)\n    throw new InvalidOperationException(\"Cannot FromSql on this hierarchy node; query the root.\");","typeGuard":"static bool CanFromSql(IEntityType e)\n    => e.BaseType == null && !e.GetDirectlyDerivedTypes().Any()\n       || e.FindDiscriminatorProperty() is not null;","tryCatchPattern":"try { return await db.Set<T>().FromSqlRaw(sql).ToListAsync(); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"does not contain a discriminator\"))\n{\n    // fall back to querying the root and filtering\n    return await db.Set<TRoot>().FromSqlRaw(sql).OfType<T>().ToListAsync();\n}","preventionTips":["Always call FromSql on the hierarchy root, not on derived sets.","Configure HasDiscriminator when using TPH with raw SQL.","Prefer SqlQueryRaw<T> for leaf-type ad-hoc queries that bypass inheritance."],"tags":["inheritance","fromsql","discriminator","tph","tpt"],"backgroundTag":null,"analyzedSha":"3a2006ef569de08368d59db5e1468aa8f407e4f8","analyzedAt":"2026-08-11T23:42:04.146Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}