with sharing only enforces record-level access — it leaves field-level security (FLS) and object CRUD unenforced. To enforce security at finer granularity — a single SOQL query, a single DML, or a specific code path — Salesforce gives you several modern tools: WITH USER_MODE / WITH SYSTEM_MODE on SOQL/DML, Security.stripInaccessible(), the older WITH SECURITY_ENFORCED clause, and explicit Schema.sObjectType.X.isAccessible() / isUpdateable() / isCreateable() / isDeletable() checks. Each operates at a different scope so you can mix them.
WITH USER_MODE — the modern one-stop clause
Added in API v60+, WITH USER_MODE on a SOQL or DML statement enforces sharing, FLS, and CRUD as the running user — in one keyword. It’s the cleanest replacement for hand-rolled enforcement.
public without sharing class OrderService {
public List<Order> userVisibleOrders() {
// Enforces sharing + FLS + CRUD as the running user,
// even though the class is 'without sharing'
return [SELECT Id, OrderNumber, TotalAmount
FROM Order
WITH USER_MODE];
}
public void closeOrder(Id orderId) {
Order o = new Order(Id = orderId, Status = 'Closed');
update as user o; // DML equivalent of USER_MODE
}
}
as system is the opposite — explicit elevation. Both make intent obvious in the code.
Security.stripInaccessible() — sanitize records before/after DML
stripInaccessible(AccessType, records) removes fields and records the user can’t read/edit, returning a sanitized list. Useful when you accept a payload from an LWC and want to forward it to DML without exposing fields the user shouldn’t be able to write.
public without sharing class AccountUpdateService {
public static void updateFromUi(List<Account> incoming) {
SObjectAccessDecision decision =
Security.stripInaccessible(AccessType.UPDATABLE, incoming);
// decision.getRecords() now contains only fields the user can update
update decision.getRecords();
}
}
AccessType values: READABLE, CREATABLE, UPDATABLE, UPSERTABLE.
WITH SECURITY_ENFORCED — the older FLS clause
Pre-USER_MODE, WITH SECURITY_ENFORCED on SOQL enforced FLS and object CRUD on the queried fields. It throws an exception if any selected field is inaccessible, rather than silently stripping.
List<Contact> cs = [
SELECT Id, Name, Email
FROM Contact
WITH SECURITY_ENFORCED
];
Use USER_MODE instead in new code — same effect, more flexible.
Explicit Schema.sObjectType checks
The lowest-level mechanism — used heavily before stripInaccessible and USER_MODE existed:
if (!Schema.sObjectType.Account.fields.AnnualRevenue.isUpdateable()) {
throw new MyAppException('No update access on AnnualRevenue');
}
if (!Schema.sObjectType.Case.isCreateable()) {
throw new MyAppException('No create access on Case');
}
Still relevant for one-off checks or for conditional UI logic in Apex helpers, but verbose for bulk operations.
How to pick the right tool per scope
| Scope | Tool |
|---|---|
| Whole class — record sharing only | with sharing / without sharing / inherited sharing |
| Single SOQL — sharing + FLS + CRUD | WITH USER_MODE |
| Single DML — sharing + FLS + CRUD | as user / as system on insert/update/upsert/delete |
| Single SOQL — FLS + CRUD only | WITH SECURITY_ENFORCED (legacy) |
| Bulk sanitize before DML | Security.stripInaccessible() |
| One field, conditional logic | Schema.sObjectType.X.fields.Y.isUpdateable() |
| One object, conditional logic | Schema.sObjectType.X.isCreateable() etc. |
A combined example
public inherited sharing class CaseClosingService {
public static void closeAndAudit(Id caseId, String reason) {
// 1. Object CRUD check
if (!Schema.sObjectType.Case.isUpdateable()) {
throw new MyAppException('No update access on Case');
}
// 2. Read with full enforcement
Case c = [SELECT Id, Status, OwnerId FROM Case WHERE Id = :caseId WITH USER_MODE];
c.Status = 'Closed';
c.Reason = reason;
// 3. Strip any inaccessible fields the LWC might have sent
SObjectAccessDecision d =
Security.stripInaccessible(AccessType.UPDATABLE, new List<Case>{ c });
// 4. DML in USER mode — sharing + FLS + CRUD
update as user d.getRecords();
}
}
Why interviewers ask this
Knowing only with sharing is the classic junior trap. Senior developers know with sharing is one of several tools, that FLS and CRUD need their own enforcement, and that the modern USER_MODE / stripInaccessible pattern is what Salesforce expects on AppExchange security reviews today.
Verified against: Apex Developer Guide — Enforcing Object and Field Permissions, WITH USER_MODE, and Sharing & Visibility Architect resources. Last reviewed 2026-05-17.