Appnigma

What Are the 5 Map Rules in Salesforce?

salesforce map rules

Mar 18, 2026

12 min read

What Are the 5 Map Rules in Salesforce?

QUICK ANSWER: The 5 map rules in Salesforce Apex are:

(1) keys must be unique,

(2) values can be duplicates,

(3) keys must be primitive data types,

(4) values can be any data type, and (5) String keys are

case-sensitive. These rules govern how the Map collection type behaves in Apex and appear

frequently in Salesforce developer certification exams.

If you have been studying for a Salesforce Developer or Platform App Builder certification, you have almost certainly hit this question: what are the 5 map rules in Salesforce? And if you are working in an Apex codebase day to day, understanding exactly how Maps enforce these rules in practice is the difference between writing bulletproof trigger logic and spending Friday afternoon chasing a mysterious null pointer exception.

In this guide we walk through all five rules in depth, with working code examples, common bugs each rule causes, and how Maps fit into the broader picture of Apex collections. We also cover essential Map methods, when to use a Map over a List or Set, and how Appnigma uses Maps inside managed package development.

What Is a Map in Salesforce Apex?

A Map in Salesforce Apex is a collection of key-value pairs where each unique key maps to a single value. It is the most powerful of the three Apex collection types (List, Set, Map) and the one most closely tied to performance in trigger logic and bulk operations. Think of it like a dictionary: you look up a word (the key) and get back a definition (the value). Each word appears only once, but two words can share the same definition.

Basic Map declaration syntax (code block):

// Basic Map declaration

Map<String, String> countryCurrency = new Map<String, String>();

countryCurrency.put('United States', 'Dollar');

countryCurrency.put('Japan', 'Yen');

countryCurrency.put('India', 'Rupee');

System.debug(countryCurrency.get('Japan')); // Output: Yen

Maps are defined with the keyword Map followed by two data types in angle brackets: the key type first, the value type second.

The 5 Map Rules in Salesforce

Here are all five rules at a glance, followed by a deep dive on each.

[@portabletext/react] Unknown block type "table", specify a component for it in the `components.types` prop

Rule 1: Keys Must Be Unique

Every key in a Salesforce Apex Map must be unique. This is the most fundamental rule and the one with the most practical impact on your code. When you call put(key, value) with a key that already exists in the Map, Apex does not throw an error. It silently replaces the previous value.

Map<String, Integer> scores = new Map<String, Integer>();

scores.put('Alice', 85);

scores.put('Bob', 90);

scores.put('Alice', 95); // Overwrites 85 — no error thrown

System.debug(scores.get('Alice')); // Output: 95

System.debug(scores.size()); // Output: 2 (not 3)

COMMON BUG: Building a Map inside a loop and expecting to accumulate multiple values per key is a classic mistake.

Each iteration on the same key replaces the previous value. If you need multiple values per key,

use Map<String, List<SomeType>> instead and append to the list on each iteration.

The ID-keyed Map Pattern

The most common application of the unique-keys rule is building a Map keyed by Salesforce record ID. Because every record has a globally unique 18-character ID, you can build a lookup Map from a SOQL query result in a single line and retrieve any record by its ID in constant time. This pattern is critical for governor limit compliance in bulk triggers.

// Single-line Map from SOQL query result

Map<Id, Account> accountMap = new Map<Id, Account>(

[SELECT Id, Name, Industry FROM Account WHERE Id IN :trigger.newMap.keySet()]

);

// Retrieve any Account by its ID in O(1) time

Account acc = accountMap.get(someAccountId);

Rule 2: Values Can Be Duplicates

While keys must be unique, values in a Salesforce Apex Map have no such restriction. Multiple distinct keys can all point to the same value. This is the asymmetry that distinguishes a Map from a Set: a Set enforces uniqueness on its elements; a Map only enforces uniqueness on its keys.

Map<String, String> teamAssignments = new Map<String, String>{

'Alice' => 'Engineering',

'Bob' => 'Engineering', // Same value, different key

'Priya' => 'Marketing',

'Carlos' => 'Engineering' // Values can repeat freely

};

System.debug(teamAssignments.size()); // Output: 4

FROM THE FIELD — Sunny Chauhan, Appnigma AI: Inside our managed package builds we use duplicate values constantly when constructing permission Maps.

We map feature names (keys) to permission set names (values), and several features share the same

permission set. This is textbook Rule 2. The Map structure is still clean and lookups are fast

because the value side carries no uniqueness obligation whatsoever.

Rule 3: Keys Must Be Primitive Data Types

Map keys in Salesforce Apex are restricted to primitive data types. Attempting to use a non-primitive type as a key causes a compile-time error. Salesforce enforces this restriction because Map key equality and hashing require deterministic behaviour that primitives provide and complex objects do not.

[@portabletext/react] Unknown block type "table", specify a component for it in the `components.types` prop

// VALID: ID as key (most common pattern in triggers)

Map<Id, Contact> contactMap = new Map<Id, Contact>();

// VALID: String as key

Map<String, Decimal> pricingMap = new Map<String, Decimal>();

// COMPILE ERROR: sObject cannot be a key

// Map<Account, String> badMap = new Map<Account, String>(); // ERROR

// COMPILE ERROR: List cannot be a key

// Map<List<String>, Integer> badMap2 = new Map<List<String>, Integer>(); // ERROR

Rule 4: Values Can Be Any Data Type

While keys are restricted to primitives, the value side of a Map has almost no restrictions. Map values can be any primitive type, any sObject, any Apex class instance, other collections (List, Set, or Map), and nested collections up to five levels deep.

  • Any primitive type (String, Integer, Boolean, Decimal, etc.)

  • Any sObject (Account, Contact, Opportunity, custom objects)

  • Any Apex class instance (standard or user-defined)

  • Other collections: List, Set, or another Map

  • Nested collections up to five levels deep

// Value = sObject (most common pattern)

Map<Id, Account> accountMap = new Map<Id, Account>(

[SELECT Id, Name FROM Account LIMIT 100]

);

// Value = List of sObjects (parent-child grouping)

Map<Id, List<Contact>> contactsByAccount = new Map<Id, List<Contact>>();

// Value = Integer (counting / aggregation)

Map<String, Integer> recordCounts = new Map<String, Integer>();

// Value = another Map (nested lookup)

Map<String, Map<String, Boolean>> featureMatrix = new Map<String, Map<String, Boolean>>();

The Parent-Child Grouping Pattern

The most powerful use of complex value types is the parent-child grouping pattern, where you group child records by their parent ID to eliminate nested SOQL queries:

// Group Contacts by AccountId — one SOQL query, no nested loops

Map<Id, List<Contact>> contactsByAccountId = new Map<Id, List<Contact>>();

for (Contact c : [SELECT Id, Name, AccountId FROM Contact WHERE AccountId != null]) {

if (!contactsByAccountId.containsKey(c.AccountId)) {

contactsByAccountId.put(c.AccountId, new List<Contact>());

}

contactsByAccountId.get(c.AccountId).add(c);

}

// Retrieve all Contacts for any Account in O(1)

List<Contact> acmeContacts = contactsByAccountId.get(someAccountId);

NESTING LIMIT: Map values can be nested collections, but Salesforce caps nesting at five levels deep.

Exceeding five levels causes a compile error. In practice, anything beyond three

levels is a design smell — consider a custom Apex class to hold the data instead.

Rule 5: String Keys Are Case-Sensitive

This is the rule that trips up the most developers and appears most frequently in certification exam questions. When the key type is String, Salesforce Apex Maps treat case as significant. The strings 'Account', 'ACCOUNT', and 'account' are three completely separate keys.

Map<String, Integer> myMap = new Map<String, Integer>();

myMap.put('Account', 1);

myMap.put('ACCOUNT', 2);

myMap.put('account', 3);

System.debug(myMap.size()); // Output: 3

System.debug(myMap.get('Account')); // Output: 1

System.debug(myMap.get('ACCOUNT')); // Output: 2

System.debug(myMap.get('account')); // Output: 3

System.debug(myMap.containsKey('aCcOuNt')); // Output: false

How to Defend Against Case-Sensitivity Bugs

Normalise all String keys to a consistent case before they enter the Map. Always lowercase or always uppercase — be consistent across your codebase:

// Normalize keys to lowercase before every put() and get()

Map<String, Integer> safeMap = new Map<String, Integer>();

String inputKey = 'ACCOUNT';

safeMap.put(inputKey.toLowerCase(), 42);

// Retrieval also normalises before lookup

Integer val = safeMap.get(inputKey.toLowerCase()); // Returns 42 reliably

FROM THE FIELD — Sunny Chauhan, Appnigma AI: The case-sensitivity rule caused a production bug in a managed package we deployed early in

Appnigma's history. We were building a Map keyed off incoming API payloads where field names

arrived in different cases depending on the client system. We were getting intermittent null

returns from get() that were invisible in unit tests because test data always came in correctly

cased. The fix took five minutes. We now enforce lowercase normalization in every String-keyed

Map across the codebase via a utility method, and it is part of our code review checklist.

Apex Collections Comparison: Map vs List vs Set

[@portabletext/react] Unknown block type "table", specify a component for it in the `components.types` prop

Essential Apex Map Methods

[@portabletext/react] Unknown block type "table", specify a component for it in the `components.types` prop

The keySet() Pattern in SOQL Queries

One of the highest-value Map patterns in trigger development is using keySet() directly inside a SOQL IN clause:

// Build a Map from trigger records

Map<Id, Account> accountMap = new Map<Id, Account>(

[SELECT Id, Name, BillingState FROM Account WHERE Id IN :trigger.newMap.keySet()]

);

// Use keySet() in a second query to pull related data

List<Opportunity> opps = [

SELECT Id, AccountId, StageName

FROM Opportunity

WHERE AccountId IN :accountMap.keySet()

];

How We Use These 5 Rules in Managed Package Development

At Appnigma, Maps are the backbone of almost every significant Apex class we ship inside managed packages. A managed package is a versioned, deployable unit that installs into a customer org, which means the Apex code inside it needs to perform flawlessly across orgs with wildly different data volumes, governor limit profiles, and configuration states.

  • Rule 1 powers our record deduplication logic. When we process incoming data from integration flows, we always build a Map keyed by the unique identifier first, which automatically collapses any duplicates in the input batch.

  • Rule 3 is why we consistently use Salesforce ID fields or field API names as keys rather than sObject references. It keeps our code clean, compiler-safe, and easy to hand off.

  • Rule 5 is documented in our internal Apex standards document. Every String-keyed Map in our codebase has a normalization step at the point of insertion. Non-negotiable in code review.

If you are building apps or ISV products on Salesforce and want to package them as managed packages for AppExchange distribution, the Appnigma platform handles the packaging mechanics so your team can focus on the business logic. Learn more in our Salesforce AppExchange App Development guide.

TL;DR — The 5 Map Rules in Salesforce

SUMMARY: All five rules at a glance for quick reference and exam prep.

  1. Keys must be unique. A duplicate key silently overwrites the existing value. No exception is thrown.

  2. Values can be duplicates. Multiple distinct keys can hold the same value.

  3. Keys must be primitive data types. Valid: String, ID, Integer, Boolean, Decimal, Long, Double, Date, Datetime, Time. sObjects, Lists, Sets, and custom objects cannot be keys.

  4. Values can be any data type. Primitives, sObjects, Apex objects, and nested collections up to 5 levels deep.

  5. String keys are case-sensitive. 'Account', 'ACCOUNT', and 'account' are three distinct keys. Always normalize String keys before use.

Frequently Asked Questions

What are the 5 map rules in Salesforce?

The 5 map rules in Salesforce Apex are: (1) keys must be unique, (2) values can be duplicates, (3) keys must be primitive data types, (4) values can be any data type, and (5) String keys are case-sensitive. These rules define how the Apex Map collection behaves and are tested in Salesforce Developer and Platform App Builder certification exams.

Can a Salesforce Apex Map have duplicate keys?

No. Map keys must be unique. If you call put() with a key that already exists, the new value silently overwrites the old one without throwing an error. The size() of the Map remains unchanged rather than increasing. This is one of the most important Map rules for both exams and real-world bug prevention.

What data types can be used as Map keys in Salesforce?

Map keys must be primitive data types: String, ID, Integer, Long, Double, Decimal, Boolean, Date, Datetime, or Time. sObjects, collections, and user-defined Apex classes cannot be used as keys and will cause a compile error.

Are Salesforce Apex Map String keys case-sensitive?

Yes. String keys are fully case-sensitive. 'Account', 'ACCOUNT', and 'account' are three separate keys. All Map methods including put(), get(), containsKey(), and remove() treat them as distinct entries. Always normalize String keys to lowercase or uppercase before inserting into or retrieving from a Map.

How many levels of nested collections can a Map contain?

A Salesforce Apex Map can contain up to five levels of nested collections. Exceeding five levels results in a compile error. In practice, nesting beyond two or three levels is a design smell — consider a custom Apex class to hold the data instead.

When should I use a Map instead of a List in Salesforce Apex?

Use a Map when you need to look up data by a meaningful identifier such as a record ID or field API name. Maps provide constant-time lookup regardless of collection size, which is critical in bulk trigger logic. Use a List when order matters, when you need index-based access, or when processing SOQL results sequentially.

Can a Salesforce Apex Map key be null?

Yes, a single null key is permitted. Calling put(null, value) is valid and get(null) retrieves it. Using null keys in production code is considered poor practice as it makes debugging significantly harder.

What is the difference between Map.keySet() and Map.values()?

keySet() returns a Set of all keys, used primarily in SOQL IN clauses. values() returns a List of all values in no guaranteed order. Use keySet() when you need keys for further queries. Use values() when you need to iterate over all values directly.

Ready to transform your Salesforce experience?

Start exploring the Salesforce Exchange today and discover apps that can take your CRM efficiency to the next level.

decorative section tag

Blog and News

Our Recent Updates