Skip to content

Settings.PrependSchemaName

Simon Hughes edited this page Aug 30, 2026 · 1 revision

Settings.PrependSchemaName

Puts the schema name in front of a generated class name, so two schemas can each have an Order table without colliding.

Type bool
Default true
Applies to EF 6 and EF Core
Databases SQL Server, PostgreSQL and Oracle. MySQL has no schema within a database; SQLite is always main
In Database.tt? Yes

What it does

dbo.Order and sales.Order cannot both generate a class called Order. So by default, any table outside the default schema gets its schema prepended: sales.Order becomes sales_Order.

Two details people get wrong:

  • The schema is prepended exactly as the database spells it, not PascalCased. It is sales_Order, not Sales_Order.
  • The default schema is never prepended. Which schema counts as default is per-database - see Settings.DefaultSchema.

Example

The fixture has dbo.Category, dbo.Product and sales.Order.

Settings.PrependSchemaName = true (default)

public interface IMyDbContext : IDisposable
public class MyDbContext : DbContext, IMyDbContext
public class MyDbContextFactory : IDesignTimeDbContextFactory<MyDbContext>
public class Category
public class Product
public class sales_Order
public class CategoryConfiguration : IEntityTypeConfiguration<Category>
public class ProductConfiguration : IEntityTypeConfiguration<Product>
public class sales_OrderConfiguration : IEntityTypeConfiguration<sales_Order>

Settings.PrependSchemaName = false

public interface IMyDbContext : IDisposable
public class MyDbContext : DbContext, IMyDbContext
public class MyDbContextFactory : IDesignTimeDbContextFactory<MyDbContext>
public class Category
public class Order
public class Product
public class CategoryConfiguration : IEntityTypeConfiguration<Category>
public class OrderConfiguration : IEntityTypeConfiguration<Order>
public class ProductConfiguration : IEntityTypeConfiguration<Product>

sales_Order becomes Order. The table mapping is unchanged - the configuration still says builder.ToTable("Order", "sales").

When to change it

Leave it true unless you have looked and confirmed there are no clashes. It is a safety net, and it fails loudly rather than silently: a clash you did not prevent becomes a compiler error.

Turn it off when every table name is unique across schemas, which is common when schemas are used for organisation rather than for namespacing. sales_Order, sales_Invoice and sales_Customer are ugly for no benefit if nothing in dbo shares those names.

Better: turn it off per schema. Settings.PrependSchemaNameForTable keeps the safety net on everywhere except the schemas you have checked:

Settings.PrependSchemaNameForTable = table =>
    !table.Schema.DbName.Equals("sales", StringComparison.OrdinalIgnoreCase);

That is almost always the right answer, and it is not in the shipped Database.tt, so most people never find it.

Gotchas

Turning it off invites silent collisions. Two tables generating the same class name produce a compiler error pointing at generated code, which is a confusing place to start debugging.

It affects stored procedures too, and they have their own per-procedure override, Settings.PrependSchemaNameForStoredProcedure.

On SQL Server, the default schema is SCHEMA_NAME(), not dbo. It is the connected login's default schema. If yours is not dbo, then dbo is prepended and your dbo tables generate as dbo_Order. This surprises people who connect as a non-standard user.

SQLite forces it off. The reader sets PrependSchemaName = false during initialisation because everything is in main. Setting it in your .tt has no effect there.

Foreign key navigation properties honour the global setting but not the per-table callback. A relationship crossing into a schema you exempted with PrependSchemaNameForTable can still use the prefixed name. Check the generated navigation properties after exempting a schema other schemas point at.

See also

Clone this wiki locally