> ## Content Index
> Fetch the complete content index at: https://www.cloudguy.us/llms.txt
> Use this file to discover other available public pages before exploring further.

# Hitting the Claims Mapping Policy 50 Limit in Entra ID
- URL: https://www.cloudguy.us/hitting-the-claims-mapping-policy-50-limit-in-entra-id/
- Published: 2026-10-24T14:39:53.000Z
- Updated: 2026-10-24T14:39:53.000Z
- Author: Matthew Jacobs

Whoah…. okay, maybe this title isn’t as long as my SAML certificate notification post, but the topic sure likes to sprawl.

Let’s say you’re mid–SSO integration. The app isn’t a simple gallery walkthrough. It’s the kind that used to live on AD FS with a claim rule set that looked like a novel. You’re past NameID. Past the happy-path attributes. You’ve decided the portal Attributes & Claims blade isn’t going to cut it — too many transforms, too much repeatable config — so you reach for a **Claims Mapping Policy**.

You wire up the JSON. You assign it to the service principal. You test.

And then… half the claims you carefully defined just don’t show up in the assertion.

No hard error. No “you exceeded the limit” banner. Just missing attributes and a Monday morning ticket that says SSO is “randomly” broken.

Welcome to **50**.

## Claims Mapping Policy vs the portal (don’t mix them up)

Before we talk about the ceiling, we need to name the tool correctly.

### Portal: Attributes & Claims

Enterprise app → Single sign-on → **Attributes & Claims**. Clicky UI. Claim conditions. Group claims. Great for most SaaS apps.

There’s also **Custom Claims Policy (Preview)** in Microsoft Graph, which shares the *same underlying config* as that portal blade — so you can manage those claims via Graph *or* the admin center.

### Claims Mapping Policy (CMP)

A first-class policy object (`claimsMappingPolicy`) you create in Graph/PowerShell and **assign to a service principal**. One policy can be linked to multiple apps. You define `ClaimsSchema`, optional `ClaimsTransformation` / `ClaimsTransformations`, optional `GroupFilter`, `IncludeBasicClaimSet`, and friends in JSON.

Microsoft is blunt about precedence:

> **Claims Mapping Policy supersedes** both Custom Claims Policy and the claims customization offered through the Microsoft Entra admin center.

Once a CMP is assigned, tokens for that app **ignore** the portal / Custom Claims Policy config. The Attributes & Claims blade often shows something like “This configuration was overwritten by a claim mapping policy created via Graph/PowerShell.” That’s not a bug — that’s the policy winning.

Notes:

- CMP is great when you need automation, reusable policy, or claim shapes the UI doesn’t express cleanly.
- CMP is *not* great if you still want colleagues editing the same map in the portal later. Pick a source of truth and stick to it.

Docs: [Claims customization](https://learn.microsoft.com/en-us/entra/identity-platform/reference-claims-customization?ref=cloudguy.us) · [Claims customization using PowerShell](https://learn.microsoft.com/en-us/entra/identity-platform/claims-customization-powershell?ref=cloudguy.us) · [claimsMappingPolicy resource](https://learn.microsoft.com/en-us/graph/api/resources/claimsmappingpolicy?ref=cloudguy.us)

## The 50 that bites: ClaimsSchema

Here’s the limit that stopped me cold on a recent SSO integration.

From the Graph `claimsMappingPolicy` docs:

| Policy property          | Documented max              | What happens over the limit                    |
| ------------------------ | --------------------------- | ---------------------------------------------- |
| **ClaimsSchema**         | **50** claim schema entries | Entries after 50 are **ignored** — not emitted |
| **ClaimsTransformation** | **50** transformations      | Transformations after 50 are **ignored**       |

Read that again: **ignored**. Not rejected on create. Not called out in the token with a friendly overage claim. Just… absent.

So if you migrate a chunky AD FS rule set into one giant `ClaimsSchema` array — employee ID, department, cost center, site code, three flavors of NameID logic, a dozen app-specific URIs, plus intermediate schema entries that only exist to feed transformations — you can sail past 50 without the create API yelling at you. The policy saves. The sign-in “works.” The 51st claim never leaves the building.

That’s the failure mode. Silent truncation of your carefully authored map.

### Why 50 arrives faster than you think

A few ways the schema budget evaporates:

1. **One AD FS issuance rule ≠ one Entra schema entry.** Transforms often need an input schema entry *and* an output schema entry that points at `Source: transformation`.
2. **Duplicates.** Emitting the same user attribute under two SAML URIs still costs two schema rows.
3. **“Just in case” claims.** Porting every historical AD FS claim “because the vendor might need it” is how you invent a limit incident.
4. **Basic claim set confusion.** `IncludeBasicClaimSet: true` still emits the basic set *in addition to* your schema — it does **not** give you free schema slots. Setting it `false` means you must put anything you still need into `ClaimsSchema` yourself (and those count).

## The other ceilings (still real, still adjacent)

CMP’s 50 isn’t the only quota in this neighborhood. Keep them straight so you don’t debug the wrong wall:

| Feature                              | Limit / rule                                           | Why you care                               |
| ------------------------------------ | ------------------------------------------------------ | ------------------------------------------ |
| CMP **ClaimsSchema**                 | **50** entries; extras ignored                         | This post’s villain                        |
| CMP **ClaimsTransformation**         | **50** transforms; extras ignored                      | Same silent failure mode                   |
| Portal / SAML **regex** transforms   | Max **20** total regex replacements                    | Documented under SAML claims customization |
| Portal **claim conditions** – groups | **50 unique groups** across all claims on the app      | Different “50” — conditional claim sources |
| SAML **groups** claim                | **150** memberships (incl. nested in the general case) | Missing groups / overage                   |
| JWT **groups** claim                 | **200**                                                | Same problem, higher ceiling               |
| Group **filtering**                  | Only if user in **≤ 1,000** groups                     | Filter skipped → overage                   |
| Groups assigned to the app           | **Direct** membership only                             | Nesting surprises                          |
| Portal transforms per claim          | Max **2** chained                                      | UI constraint                              |

Group claims and claim conditions still matter on SSO projects — especially if the app wants a groups dump *and* a CMP. Just don’t conflate “50 unique groups for claim conditions” with “50 ClaimsSchema entries on a CMP.” Same number. Different knobs.

Docs: [Entra service limits](https://learn.microsoft.com/en-us/entra/identity/users/directory-service-limits-restrictions?ref=cloudguy.us) · [Configure group claims](https://learn.microsoft.com/en-us/entra/identity/hybrid/connect/how-to-connect-fed-group-claims?ref=cloudguy.us) · [Customize SAML token claims](https://learn.microsoft.com/en-us/entra/identity-platform/saml-claims-customization?ref=cloudguy.us)

## How CMP talks to groups

CMP can include a **GroupFilter** in the policy definition: match on `displayname` or `samaccountname`, with `prefix` / `suffix` / `contains`. Useful for shrinking what goes into the groups claim.

That filter is still subject to the broader group-claim rules (150 SAML / 200 JWT, filter eligibility ≤ 1,000 memberships, assigned-groups = direct only). CMP doesn’t give you a free pass around those.

If you’re doing multi-pattern group filtering, the native filter is effectively one pattern string — regex-style transforms on a customized group claim name are the usual escape hatch (and then you’re back in regex-replacement budget land).

## Assigning the policy (the part people forget to verify)

High-level flow:

1. Create the policy: `New-MgPolicyClaimMappingPolicy` (or `POST /policies/claimsMappingPolicies`).
2. Assign it to the **enterprise app’s service principal**: `New-MgServicePrincipalClaimMappingPolicyByRef`.
3. Confirm assignment: `GET .../servicePrincipals/{id}/claimsMappingPolicies`.
4. For APIs/OIDC resource apps, also mind `acceptMappedClaims` / token version on the application object when you’re emitting mapped claims into access tokens.
5. **Test the actual token** (SAML assertion or JWT at jwt.ms). Do **not** trust the Attributes & Claims blade as a mirror of the CMP — it isn’t one.

Scopes you’ll need typically include `Policy.ReadWrite.ApplicationConfiguration` (and related read scopes). Claims-mapping policies can only be assigned to service principals — not set as an org-wide default.

Docs: [Claims customization using PowerShell](https://learn.microsoft.com/en-us/entra/identity-platform/claims-customization-powershell?ref=cloudguy.us) · [Customize claims with CMP in Microsoft Graph](https://learn.microsoft.com/en-us/graph/how-to-claims-customization?ref=cloudguy.us)

## What breaks in the wild

Patterns that look a lot like “SSO is flaky” but are really quota-shaped:

- **Claims 51+ silently missing** → ClaimsSchema over 50; policy created fine; assertion incomplete.
- **Transforms that “don’t run”** → past the 50 transformation entries, or the output schema row that should emit them got truncated.
- **Portal edits do nothing** → CMP is assigned and superseding; you’re editing a ghost UI.
- **AD FS lift-and-shift blowouts** → every historical issuance/transform rule dumped into one JSON → 50 arrives on day one.
- **Groups still empty / overage** → you fixed CMP, but the user crossed 150 (SAML) or the app ignored overage / can’t call Graph.
- **“Groups assigned to the app” + nesting** → user nested under an assigned group; direct-only rule bites.

## Practical ways out when you hit 50

If the CMP ClaimsSchema wall is the problem, these are the moves that actually help:

1. **Count before you commit.** Script a check: length of `ClaimsSchema` and `ClaimsTransformation` arrays. Treat 50 as a hard design budget, not a surprise.
2. **Consolidate.** One claim with a clear URI beats three legacy aliases “for compatibility” unless the SP truly needs all three.
3. **Drop dead weight.** If the vendor’s SAML tracer never consumed a claim in UAT, it doesn’t need a schema row in prod.
4. **Prefer app roles** for authorization when the app can take them — smaller tokens, clearer semantics, less pressure to invent claim sprawl (nested groups still aren’t in play for app-role assignment via groups).
5. **Emit Object IDs for groups**, not display names, when groups are still required — and prefer **groups assigned to the application** so you stay intentional under 150.
6. **Simplify transforms.** Every Join/Extract/RegexReplace chain tends to cost schema + transformation slots. Sometimes a synced extension attribute computed upstream is cheaper than three transforms in the token pipeline.
7. **Don’t duplicate schema entries** for the same source just to rename things twice — pick the claim type the app documents.
8. **When the app can call Microsoft Graph**, let it fetch full membership / profile data instead of stuffing the universe into SAML.
9. **Split responsibility thoughtfully.** One reusable CMP across similar apps is fine; one monster policy that tries to satisfy five unrelated vendors is how you meet 50 with style.
10. **Stay on CMP or stay on the portal — not both.** If you need GUI + Graph on the *same* config, look at Custom Claims Policy (Preview) instead of CMP; know that CMP will keep winning (and locking the blade) if it’s assigned.

## Quick reference

| Question                                               | Short answer                                                      |
| ------------------------------------------------------ | ----------------------------------------------------------------- |
| What’s the CMP schema limit?                           | **50** ClaimsSchema entries                                       |
| What’s the CMP transform limit?                        | **50** ClaimsTransformation entries                               |
| What happens at 51?                                    | **Silent ignore** — not in the token                              |
| Does CMP override the portal?                          | **Yes** — supersedes Attributes & Claims and Custom Claims Policy |
| Where do you assign it?                                | To the app’s **service principal**                                |
| Is portal claim-conditions “50 groups” the same limit? | **No** — related neighborhood, different feature                  |
| SAML groups ceiling?                                   | **150** (JWT **200**)                                             |

## Final thoughts

Claims Mapping Policy is powerful. It’s also quota-shaped — and unlike a certificate expiry, it won’t email you 60 / 30 / 7 days before you have a bad time.

If you treat Entra like “AD FS but in the cloud, paste every issuance rule into JSON,” you’ll meet **50** the hard way: a policy that saves, a sign-in that “works,” and an assertion that’s missing the one attribute the app actually authorizes on.

If you treat ClaimsSchema like a budget — count entries, consolidate early, prefer app roles or Graph where you can, and keep transforms intentional — your SSO integrations stay about coffee instead of hunting ghosts in a SAML tracer.

Stay curious. Count your schema entries. And maybe don’t port the 2008 claim rule named `EmitEverythingIncludingTheKitchenSink` without a second look.

### References

- [claimsMappingPolicy resource type (ClaimsSchema / ClaimsTransformation = 50; extras ignored)](https://learn.microsoft.com/en-us/graph/api/resources/claimsmappingpolicy?ref=cloudguy.us)
- [Claims customization (CMP supersedes portal / Custom Claims Policy; GroupFilter; transforms)](https://learn.microsoft.com/en-us/entra/identity-platform/reference-claims-customization?ref=cloudguy.us)
- [Claims customization using PowerShell and Claims Mapping Policy (create + assign to SP)](https://learn.microsoft.com/en-us/entra/identity-platform/claims-customization-powershell?ref=cloudguy.us)
- [Customize claims with Claims Mapping Policy in Microsoft Graph](https://learn.microsoft.com/en-us/graph/how-to-claims-customization?ref=cloudguy.us)
- [Customize SAML token claims (claim conditions 50 groups; regex max 20; portal transforms)](https://learn.microsoft.com/en-us/entra/identity-platform/saml-claims-customization?ref=cloudguy.us)
- [Configure group claims](https://learn.microsoft.com/en-us/entra/identity/hybrid/connect/how-to-connect-fed-group-claims?ref=cloudguy.us)
- [Entra service limits](https://learn.microsoft.com/en-us/entra/identity/users/directory-service-limits-restrictions?ref=cloudguy.us)
- [SAML token claims reference](https://learn.microsoft.com/en-us/entra/identity-platform/reference-saml-tokens?ref=cloudguy.us)
- [Group claims, overage, and app roles](https://learn.microsoft.com/en-us/security/zero-trust/develop/configure-tokens-group-claims-app-roles?ref=cloudguy.us)