Determining the object type of a specific record ID is a common challenge for Salesforce developers, especially when working with polymorphic fields like WhatId, WhoId, or the ParentId on an Attachment. Whether you are building a generic trigger framework or a dynamic utility class, knowing exactly which sObject you are dealing with is crucial for writing robust code.
In this guide, you will learn the most efficient ways to infer the Salesforce Id sObject type, why certain methods are preferred over others, and how to handle collections of IDs effectively.
The Modern Standard: Using Id.getSObjectType()
Since API version 26.0, Salesforce has provided a streamlined, native method to identify an object's type directly from an ID instance. The Id.getSObjectType() method returns an SObjectType token, which is a lightweight reference to the object schema.
This is the highly recommended approach because it is extremely efficient in terms of CPU time and heap space. Unlike older methods, it does not require iterating through the entire global describe map.
Implementation Example
To get the API name of an object from a variable named someId, you can use the following code snippet:
// Get the sObject token and then describe it to get the name
String objectAPIName = someId.getSObjectType().getDescribe().getName();
System.debug('The object type is: ' + objectAPIName);
This approach is clean and readable. By using the SObjectType token, you can also perform direct comparisons without needing to deal with strings, which is a best practice for type safety in Apex.
Handling Collections and Polymorphic Parents
A common scenario involves iterating through a collection of records—such as Attachments—and needing to identify the types of their parent records. Because an Attachment can be linked to many different types of objects (Accounts, Contacts, Custom Objects, etc.), the ParentId field is polymorphic.
Consider this logic within an Apex trigger:
Set<Id> parentIds = new Set<Id>();
for (Attachment a : Trigger.new) {
parentIds.add(a.ParentId);
}
// How do we identify the types in this set?
for (Id pId : parentIds) {
Schema.SObjectType token = pId.getSObjectType();
System.debug('Processing record for object type: ' + token.getDescribe().getName());
}
Why This Matters for Performance
When processing large batches of data, avoiding expensive describe calls is vital. While getDescribe() is much faster than it used to be in older Salesforce releases, it is still better to cache your results if you are checking the same object type repeatedly within a loop.
The Legacy Approach: Key Prefix Matching
Before the introduction of getSObjectType(), developers had to rely on the "Key Prefix." Every Salesforce object has a unique three-character prefix that starts its ID (e.g., 001 for Account, 003 for Contact).
While you should avoid this method in modern development, understanding it is helpful for maintaining legacy codebases. The process involved fetching the global describe map and comparing prefixes:
// DO NOT USE THIS IN MODERN APEX
String myIdPrefix = String.valueOf(someId).substring(0,3); // Get the 3-character prefix
Map<String, Schema.SObjectType> gd = Schema.getGlobalDescribe();
for(Schema.SObjectType stype : gd.values())
{
Schema.DescribeSObjectResult r = stype.getDescribe();
String prefix = r.getKeyPrefix();
if(prefix != null && prefix.equals(myIdPrefix))
{
System.debug('Object type found: ' + r.getName());
break;
}
}
Why the Legacy Method is Discouraged
- Performance: Iterating through
Schema.getGlobalDescribe()is a heavy operation that consumes significant CPU time. - Complexity: It requires much more boilerplate code to achieve the same result.
- Reliability: While prefixes are generally stable, relying on string manipulation of IDs is less robust than using built-in system methods.
Best Practices for Inferring sObject Types
When working with dynamic sObject identification, keep these best practices in mind:
- Null Checks: Always ensure the ID variable is not null before calling
.getSObjectType(), or you will encounter aNullPointerException. - Use Tokens for Comparison: If you need to check if an ID belongs to a specific type, compare the tokens directly rather than strings. For example:
if (someId.getSObjectType() == Account.sObjectType). - Avoid Global Describe in Loops: Never call
Schema.getGlobalDescribe()inside aforloop. If you must use it, call it once and store the result in a static variable. - Consider 15 vs 18 Character IDs: The
getSObjectType()method works correctly regardless of whether the ID is the 15-character (case-sensitive) or 18-character (case-insensitive) version.
Common Mistakes to Avoid
One frequent mistake is assuming that all IDs in a collection will be of the same type. In polymorphic relationships (like the WhatId on a Task), a single list of IDs could contain references to Accounts, Opportunities, and Campaigns simultaneously. Always write your logic to handle multiple object types gracefully if there is any chance the ID source is polymorphic.
Another pitfall is forgetting that some system objects or internal types might not behave exactly like standard sObjects. Always test your code against the specific objects you expect to encounter in your production environment.
Frequently Asked Questions
Can I get the sObject type from a String instead of an Id variable?
Yes, but you must first cast or convert the String to an Id type. For example: Id.valueOf(myString).getSObjectType(). Note that if the string is not a valid Salesforce ID, this will throw an exception.
Does getSObjectType() work for Custom Settings or Custom Metadata?
Yes, getSObjectType() works for Custom Settings and Custom Metadata records just as it does for standard and custom objects, as they all follow the Salesforce ID structure.
Is there a limit to how many times I can call getSObjectType()?
There is no specific governor limit for calling .getSObjectType(). However, the subsequent .getDescribe() call does count toward your performance overhead, though it no longer counts against the old "100 describe calls" limit that existed in very old versions of Salesforce.
Wrapping Up
Inferring the sObject type from an ID is a fundamental skill for any advanced Salesforce developer. By using Id.getSObjectType(), you ensure your code is efficient, readable, and future-proof. Avoid the legacy approach of manual prefix matching unless you are working in an extremely old environment (pre-API v26).
By leveraging SObjectType tokens, you can build powerful, dynamic applications that react intelligently to whatever data is passed through your Apex logic. Happy coding!