The @TenantDiscriminator annotation is used with the @Multitenant annotation and the SINGLE-TABLE mulitenant type to limit what a persistence context can access in single-table mulitenancy.

Annotation Elements

Table 2-67 describes this annotation's elements.

Table 2-67 @TenantDiscriminatorColumn Properties

Annotation Element Description Default

java.lang.String columnDefinition

(Optional) The SQL fragment that is used when generating the DDL for the discriminator column.

The provider-generated SQL to create a column of the specified discriminator type.

java.lang.String contextProperty

(Optional) The name of the context property to apply to the tenant discriminator column.


DiscriminatorType discriminatorType

(Optional) The type of object/column to use as a class discriminator.


int length

(Optional) The column length for String-based discriminator types.

The column length for String-based discriminator types. Ignored for other discriminator types.

java.lang.String name

(Optional) The name of column to be used for the tenant discriminator.


boolean primaryKey

Specifies that the tenant discriminator column is part of the primary key of the tables.


java.lang.String table

(Optional) The name of the table that contains the column.

The name of the table that contains the column. If absent the column is assumed to be in the primary table. This attribute must be specified if the column is on a secondary table.


To configure single-table multi-tenancy, you must specify both of the following:

  • Annotate the entity or mapped superclass to use single-table multi-tenancy, using the @Multitenant annotation, for example:


    SINGLE_TABLE states that the table or tables (Table and SecondaryTable) associated with the given entity can be shared among tenants.


    The @Table annotation is not required, because the discriminator column is assumed to be on the primary table. However, if the discriminator column is defined on a secondary table, you must identify that table using @SecondaryTable.

  • Specify the column or columns to be used as the discriminator column, using the @TenantDiscriminatorColumn annotation, for example:

    @TenantDiscriminatorColumn(name = “TENANT_ID”)

    You can specify multiple discriminator columns by using the @TenantDiscriminatorColumns annotation, for example:

    @Table(name = "EMPLOYEE") 
        @TenantDiscriminatorColumn(name = "TENANT_ID")
        @TenantDiscriminatorColumn(name = "TENANT_CODE" contextProperty="eclipselink.tenant-code")})

Using Discriminator Columns

The following characteristics apply to discriminator columns:

  • On persist, the values of tenant discriminator columns are populated from their associated context properties.

  • Tenant discriminator columns are application definable. That is, the discriminator column is not tied to a specific column for each shared entity table. You can use TENANT_ID, T_ID, etc.

  • There is no limit on how many tenant discriminator columns an application can define.

  • Any name can be used for a discriminator column.

  • Tenant discriminator column(s) must always be used with @Multitenant(SINGLE_TABLE). You cannot specify the tenant discriminator column(s) only.

  • Generated schemas can include specified tenant discriminator columns.

  • Tenant discriminator columns can be mapped or unmapped:

    • When a tenant discriminator column is mapped, its associated mapping attribute must be marked as read only. With this restriction in place, a tenant discriminator column cannot be part of the entity identifier; it can only be part of the primary key specification on the database.

  • Both mapped and unmapped properties are used to form the additional criteria when issuing a SELECT query.

Using Single-Table Multi-Tenancy in an Inheritance Hierarchy

Inheritance strategies are configured by specifying the inheritance type (see @javax.persistence.Inheritance). Single-table multi-tenancy can be used in an inheritance hierarchy, as follows:

  • Multi-tenant metadata can be applied only at the root level of the inheritance hierarchy when using a SINGLE_TABLE or JOINED inheritance strategy.

  • You can also specify multi-tenant metadata within a TABLE_PER_CLASS inheritance hierarchy. In this case, every entity has its own table, with all its mapping data (which is not the case with SINGLE_TABLE or JOINED strategies). Consequently, in the TABLE_PER_CLASS strategy, some entities of the hierarchy may be multi-tenant, while others may not be. The other inheritance strategies can only specify multi-tenancy at the root level, because you cannot isolate an entity to a single table to build only its type.


Table 2-67 shows a number of uses of tenant discriminator columns.

Example 2-110 Using @TenantDiscriminatorColumn Annotation

/** Single tenant discriminator column **/
@Table(name = "CUSTOMER")
@TenantDiscriminatorColumn(name = "TENANT", contextProperty = "multi-tenant.id")
public Customer() {
/** Multiple tenant discriminator columns using multiple tables **/
@Table(name = "EMPLOYEE")
@SecondaryTable(name = "RESPONSIBILITIES")
    @TenantDiscriminatorColumn(name = "TENANT_ID", contextProperty = "employee-tenant.id", length = 20)
    @TenantDiscriminatorColumn(name = "TENANT_CODE", contextProperty = "employee-tenant.code", discriminatorType = STRING, table = "RESPONSIBILITIES")
public Employee() {
/** Tenant discriminator column mapped as part of the primary key on the database **/
@Table(name = "ADDRESS")
@TenantDiscriminatorColumn(name = "TENANT", contextProperty = "tenant.id", primaryKey = true)
public Address() {
/** Mapped tenant discriminator column **/
@Table(name = "Player")
@TenantDiscriminatorColumn(name = "AGE", contextProperty = "tenant.age")
public Player() {
  @Column(name="AGE", insertable="false", updatable="false")
  public int age;

Example 2-111 shows the same mappings, using the <tenant-disciminator-column> XML element in the eclipselink-orm.xml file.

Example 2-111 Using <tenant-discriminator-column> XML

<!-- Single tenant discriminator column -->
<entity class="model.Customer">
    <tenant-discriminator-column name="TENANT context-property="multi-tenant.id""/>
  <table name="CUSTOMER"/>
<!-- Multiple tenant discriminator columns using multiple tables -->
<entity class="model.Employee">
  <multitenant type="SINGLE_TABLE">
    <tenant-discriminator-column name="TENANT_ID" context-property="employee-tenant.id" length="20"/>
    <tenant-discriminator-column name="TENANT_CODE" context-property="employee-tenant.id" discriminator-type="STRING" table="RESPONSIBILITIES"/>
  <table name="EMPLOYEE"/>
  <secondary-table name="RESPONSIBILITIES"/>
<!-- Tenant discriminator column mapped as part of the primary key on the database -->
<entity class="model.Address">
    <tenant-discriminator-column name="TENANT" context-property="multi-tenant.id" primary-key="true"/>
  <table name="ADDRESS"/>
<!-- Mapped tenant discriminator column -->
<entity class="model.Player">
    <tenant-discriminator-column name="AGE" context-property="tenant.age"/>
  <table name="PLAYER"/>
    <basic name="age" insertable="false" updatable="false">
      <column name="AGE"/>

See Also