# 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.

:::tip
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.
:::

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:

```soql
SELECT Id, Owner.Name FROM Account
```

:::note
Use the name of the *relationship* (`Owner`) not the name of the *field* (`OwnerId`).
:::

**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:

```soql
SELECT 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:

  ```codesegment
  SELECT Id, Owner.Name
  FROM Task
  WHERE 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:

  ```codesegment
  SELECT Id, Who.FirstName, Who.LastName
  FROM Task
  WHERE 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:

  ```codesegment
  SELECT Id, Who.Id, Who.Type
  FROM Task
  ```

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

  ```codesegment
  SELECT Id, Who.Id, Who.Type
  FROM Task
  WHERE Who.Type='Contact'
  ```

- `What`: This field represents nonhuman objects that are associated with the record. For example:

  ```codesegment
  SELECT Id, What.Name
  FROM 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.

```soql
SELECT Id
FROM Event
WHERE 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](/docs/platform/salesforce-soql-sosl/guide/sforce-api-calls-soql-select-comparisonoperators.md) 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.

```soql
SELECT
  TYPEOF What
    WHEN Account THEN Phone, NumberOfEmployees
    WHEN Opportunity THEN Amount, CloseDate
    ELSE Name, Email
  END
FROM 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](/docs/platform/salesforce-soql-sosl/guide/sforce-api-calls-soql-select-filtering-polymorphic-relationships.md).

- `TYPEOF` isn’t allowed in queries that don’t return objects, such as [`COUNT()`](/docs/platform/salesforce-soql-sosl/guide/sforce-api-calls-soql-select-agg-functions.md) .

- `TYPEOF` can’t be used in SOQL queries that are the basis of [Streaming API PushTopics](https://developer.salesforce.com/docs/atlas.en-us.api_streaming.meta/api_streaming/pushtopic_events_intro.htm).

- `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](/docs/platform/salesforce-soql-sosl/guide/sforce-api-calls-soql-select-comparisonoperators.md#semi-joins-with-in-and-anti-joins-with-not-in). 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:

  ```soql
  SELECT Name FROM Account
  WHERE CreatedById IN
      (
      SELECT
          TYPEOF Owner
              WHEN User THEN Id
              WHEN Group THEN CreatedById
          END
      FROM CASE
      )
  ```

  The following example is valid because `TYPEOF` is only used in the outer `SELECT` clause:

  ```soql
  SELECT
      TYPEOF What
          WHEN Account THEN Phone
          ELSE Name
      END
  FROM Event
  WHERE CreatedById IN
      (
      SELECT CreatedById
      FROM Case
      )
  ```

- `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.

  ```soql
  SELECT
   TYPEOF What
    WHEN Account THEN Id, FORMAT(LastModifiedDate) LastModifiedDate__f
    WHEN Opportunity THEN Id
   END
  FROM Task
  ```

  Instead, run the same query without functions to retrieve a list of IDs.

  ```soql
  SELECT
      TYPEOF What
          WHEN Account THEN Id, LastModifiedDate
          WHEN Opportunity THEN Id
      END
  FROM Task
  ```

  Then, run a second query with functions on the resulting ID list.

  ```soql
  SELECT
      FORMAT(LastModifiedDate) LastModifiedDate__f
  FROM Account
  WHERE Id in RetrievedIdList
  ```

- `TYPEOF` can’t be used in queries with [`GROUP BY`](/docs/platform/salesforce-soql-sosl/guide/sforce-api-calls-soql-select-groupby.md), [`GROUP BY ROLLUP`](/docs/platform/salesforce-soql-sosl/guide/sforce-api-calls-soql-select-groupby-rollup.md), [`GROUP BY CUBE`](/docs/platform/salesforce-soql-sosl/guide/sforce-api-calls-soql-select-groupby-cube.md), and [`HAVING`](/docs/platform/salesforce-soql-sosl/guide/sforce-api-calls-soql-select-having.md).

## 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.

```soql
SELECT Id,
  TYPEOF What
    WHEN Account THEN Phone
    WHEN Opportunity THEN Amount
  END
FROM Event
WHERE 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:

   ```nolang
   <complexType name="Task">
     <complexContent>
       <extension base="ens:sObject">
         <sequence>
         ...
         <element name="Owner" nillable="true" minOccurs="0" type="ens:sObject"/>
         ...
         </sequence>
       </extension>
     </complexContent>
   </complexType>

   ```

2. In other versions, the type is `Name`. For example:

   ```nolang
   <complexType name="Task">
     <complexContent>
       <extension base="ens:sObject">
         <sequence>
         ...
         <element name="Owner" nillable="true" minOccurs="0" type="ens:Name"/>
         ...
         </sequence>
       </extension>
     </complexContent>
   </complexType>

   ```

This affects Java code generated from these WSDLs. For example, in `Task.java`, the Owner field is now defined as:

```nolang
private com.sforce.soap.enterprise.sobject.SObject Owner;
```

For more information about generating Java code from WSDL files, see [Setting Up Your Java Developer Environment](https://developer.salesforce.com/docs/atlas.en-us.salesforce_developer_environment_tipsheet.meta/salesforce_developer_environment_tipsheet/salesforce_developer_environment_overview.htm).

**See Also**

- [*SOQL and SOSL Reference*: Understanding Relationship Query Limitations](https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_relationships_query_limits.htm)
- [*Apex Reference Guide*: Working with Polymorphic Relationships in SOQL Queries](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/langCon_apex_SOQL_polymorphic_relationships.htm)
- [*Apex Reference Guide*: getSObject(field)](https://developer.salesforce.com/docs/atlas.en-us.apexref.meta/apexref/apex_methods_system_sobject.htm#apex_System_SObject_getSObject\_2)
