Understanding Relationship Fields and Polymorphic Fields

In a polymorphic relationship, the referenced object of the relationship can be one of several different types of object.

Here's an overview of the terminology used in this document.

  • Name as a label on the Salesforce UI of certain types of objects, such as Tasks. Represents the related person, usually a Lead or Contact.
  • WhoId: The corresponding API name of the Name. Used in code or in API calls.
  • Related To as a label on the Salesforce UI of certain types of objects, such as Tasks. Represents the related object, usually an Account. Not a person object.
  • WhatId: The corresponding API name of the Related To.
  • Who: The value of relationshipName of the Name. Used in queries as a stand-in for Name.
  • What: The value of relationshipName of the Related To. Used in queries as a stand-in for Related To.

Tip

Some fields are relationship fields, which means they can be used to get information about a related object. And some of those relationship fields are polymorphic fields. A polymorphic field is one where the related object might be one of several different types of objects. For example, the Who relationship field of a Task can be a Contact or a Lead.

To determine what kind a field is, call describeSObjects() on the object and examine the properties for the field.
  1. If relationshipName is not null, the field is a relationship field.
  2. If, in addition, namePointing is true, polymorphicForeignKey is true, and referenceTo has more than one referenced object type, then the field is polymorphic.

Example of a Relationship Field

The OwnerId field of the Account object has the following properties:
  • relationshipName = Owner
  • namePointing = false
  • referenceTo = User
This means it is a relationship field. Use the relationshipName as a pseudo field to get information about the related object, whose type is specified in the referenceTo field. For example, you can use the following SOQL query:
1SELECT Id, Owner.Name FROM Account

Use the name of the relationship (Owner) not the name of the field (OwnerId).

Note

Example of a Polymorphic Field

The OwnerId field of the Event object has the following properties:
  • relationshipName = Owner
  • namePointing = true
  • polymorphicForeignKey = true
  • referenceTo = Calendar, User

This means it is a polymorphic field. Owner could be a Calendar, or a User. For example, you can use the following SOQL query:

1SELECT Id, Owner.Name FROM Event WHERE Owner.Type = 'User'

Using Polymorphic Fields

You can use polymorphic fields several ways.
  • You can use the polymorphic field for the relationship.
  • You can use the Type qualifier on a polymorphic field.
  • You can use a TYPEOF clause in a query.
You can also combine these techniques for complex queries.

Common Polymorphic Fields

Common polymorphic fields include:

  • Owner: This field represents the parent of the record. For example:
    1SELECT Id, Owner.Name
    2FROM Task
    3WHERE Owner.FirstName like 'B%'

    This example query works for Task records whose owners are either Calendars or Users.

  • Who: This field represents the person associated with the record. For example:
    1SELECT Id, Who.FirstName, Who.LastName
    2FROM Task
    3WHERE Owner.FirstName LIKE 'B%'

    This example query works for Task records whose owners can be either Calendars or Users, and whose Who field can be either Contacts or Leads.

    If you'd like to know the type of object returned in a query, use Who.Type. For example:

    1SELECT Id, Who.Id, Who.Type
    2FROM Task

    Using this example, you can query all the Tasks associated with Contacts:

    1SELECT Id, Who.Id, Who.Type
    2FROM Task
    3WHERE Who.Type='Contact'
  • What: This field represents nonhuman objects that are associated with the record. For example:
    1SELECT Id, What.Name
    2FROM Event

    This example query works for Events where What can be an Account or a Solution, or any of another number of object types.

Using the Type Qualifier

You can use the Type qualifier on a field to determine the object type that’s referenced in a polymorphic relationship. Use the Type qualifier in the WHERE clause of a SELECT statement to conditionally control what’s returned from the query depending on the referenced object type. The following SELECT statement uses Type to filter the query based on the What field in Event.
1SELECT Id
2FROM Event
3WHERE What.Type IN ('Account', 'Opportunity')
At run time, this SELECT statement returns the IDs for Events that reference Accounts or Opportunities in the What field. If an Event referenced a Campaign in the What field, it wouldn’t be returned as part of this SELECT. Unlike the TYPEOF expression, object types are returned as strings from Type. You can apply any WHERE comparison operator to the object type strings, such as = (Equals) or LIKE.

Using TYPEOF

SOQL supports polymorphic relationships using the TYPEOF expression in a SELECT statement. TYPEOF is available in API version 46.0 and later. (It is also available in API version 26.0 and later as part of a Developer Preview.)

Use TYPEOF in a SELECT statement to control which fields to query for each object type in a polymorphic relationship. The following SELECT statement returns a different set of fields depending on the object type associated with the What polymorphic relationship field in an Event.
1SELECT 
2  TYPEOF What
3    WHEN Account THEN Phone, NumberOfEmployees
4    WHEN Opportunity THEN Amount, CloseDate
5    ELSE Name, Email
6  END
7FROM Event
At run time, this SELECT statement checks the object type referenced by the What field in an Event. If the object type is Account, the referenced Account’s Phone and NumberOfEmployee fields are returned. If the object type is Opportunity, the referenced Opportunity’s Amount and CloseDate fields are returned. If the object type is any other type, the Name and Email fields are returned. Note that if an ELSE clause isn’t provided and the object type isn’t Account or Opportunity, then null is returned for that Event.

Note the following considerations for TYPEOF.

  • TYPEOF can’t be used with a relationship field whose namePointing attribute is false.
  • TYPEOF can’t be used with a relationship field whose relationshipName attribute is false.
  • TYPEOF is only allowed in the SELECT clause of a query. You can filter on the object type of a polymorphic relationship using the Type qualifier in a WHERE clause. For details, see Filter on Polymorphic Relationship Fields.
  • TYPEOF isn’t allowed in queries that don’t return objects, such as COUNT() .
  • TYPEOF can’t be used in SOQL queries that are the basis of Streaming API PushTopics.
  • TYPEOF can’t be used in SOQL used in Bulk API.
  • TYPEOF expressions can’t be nested. For example, you can’t use TYPEOF inside the WHEN clause of another TYPEOF expression.
  • TYPEOF isn’t allowed in the SELECT clause of a semi-join query. You can use TYPEOF in the SELECT clause of an outer query that contains semi-join queries. The following example is not valid because TYPEOF is used in the semi-join query:
    1SELECT Name FROM Account
    2WHERE CreatedById IN
    3    (
    4    SELECT 
    5        TYPEOF Owner
    6            WHEN User THEN Id
    7            WHEN Group THEN CreatedById
    8        END
    9    FROM CASE
    10    )
    The following example is valid because TYPEOF is only used in the outer SELECT clause:
    1SELECT 
    2    TYPEOF What
    3        WHEN Account THEN Phone
    4        ELSE Name
    5    END
    6FROM Event
    7WHERE CreatedById IN
    8    (
    9    SELECT CreatedById
    10    FROM Case
    11    )
  • TYPEOF can’t be used in queries with functions in the SELECT clause. The following example is not valid because the TYPEOF includes the FORMAT function.
    1SELECT
    2 TYPEOF What
    3  WHEN Account THEN Id, FORMAT(LastModifiedDate) LastModifiedDate__f
    4  WHEN Opportunity THEN Id
    5 END
    6FROM Task
    Instead, run the same query without functions to retrieve a list of IDs.
    1SELECT
    2    TYPEOF What
    3        WHEN Account THEN Id, LastModifiedDate
    4        WHEN Opportunity THEN Id
    5    END
    6FROM Task
    Then, run a second query with functions on the resulting ID list.
    1SELECT 
    2    FORMAT(LastModifiedDate) LastModifiedDate__f 
    3FROM Account 
    4WHERE Id in RetrievedIdList
  • TYPEOF can’t be used in queries with GROUP BY, GROUP BY ROLLUP, GROUP BY CUBE, and HAVING.

Combining TYPEOF and Type

You can combine TYPEOF and Type in a SELECT statement. The following SELECT statement uses both TYPEOF and Type to filter the query and refine the set of returned fields based on the What field in Event.
1SELECT Id,
2  TYPEOF What
3    WHEN Account THEN Phone
4    WHEN Opportunity THEN Amount
5  END
6FROM Event
7WHERE What.Type IN ('Account', 'Opportunity')
At run time, this SELECT statement always returns the ID for an Event, and then either Account.Phone, or Opportunity.Amount, depending on the object type referenced by the Event’s What field. Note that no ELSE clause has been provided. Since this statement filters based on the What field in the WHERE clause, only Events that reference either an Account or Opportunity are returned, so the ELSE clause is not needed. If an ELSE clause was included in this case, it would be ignored at run time.

Object Types in WSDLs

In the Enterprise and Tooling API WSDLs, the object type of a polymorphic field depends on the version of the API.
  1. In API version 46.0 and later (and in versions where the Developer Preview part of the SOQL Polymorphism feature is enabled), the object type is sObject. For example:
    1<complexType name="Task">
    2  <complexContent>
    3    <extension base="ens:sObject">
    4      <sequence>
    5      ...
    6      <element name="Owner" nillable="true" minOccurs="0" type="ens:sObject"/>
    7      ...
    8      </sequence>
    9    </extension>
    10  </complexContent>
    11</complexType>
  2. In other versions, the type is Name. For example:
    1<complexType name="Task">
    2  <complexContent>
    3    <extension base="ens:sObject">
    4      <sequence>
    5      ...
    6      <element name="Owner" nillable="true" minOccurs="0" type="ens:Name"/>
    7      ...
    8      </sequence>
    9    </extension>
    10  </complexContent>
    11</complexType>
This affects Java code generated from these WSDLs. For example, in Task.java, the Owner field is now defined as:
1private com.sforce.soap.enterprise.sobject.SObject Owner;
For more information about generating Java code from WSDL files, see Setting Up Your Java Developer Environment.