If you are experiencing this issue when you try to get the value from your records (post-processing), you may be running into a similar issue as http://salesforce.stackexchange.com/questions/111146/unable-to-retieve-dynamic-sobject-field-value/111151#111151. You can implement the class I describe there and just do: for (BOG_Membership__c membership : [/*query*/]) String contactName = CrossObject.get(membership, 'Contact__r.Name'); You can also just hardcode the path: String contactName = membership.Contact__r.Name; --- If you are experiencing this issue when you perform your query, you are almost certainly experiencing an issue with `Field Level Security`. I was able to reproduce the behavior you describe by creating a custom object `MyObject__c` with a `Contact` lookup `Contact__c`, and unchecking `Visible` for all profiles. To fix the problem, I clicked into the lookup field and hit the <kbd>Set Field-Level Security</kbd> button. Make sure `Visible` is checked for your profile (and anyone else who should have access). The reason the `Apex` does not blow up is, well, it was designed that way. The [Apex Developer Guide](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_keywords_sharing.htm) states that: > Apex code runs in system context. In system context, Apex code has access to all objects and fields— object permissions, field-level security, sharing rules aren’t applied for the current user. This is to ensure that code won’t fail to run because of hidden fields or objects for a user. The only exceptions to this rule are Apex code that is executed with the executeAnonymous call and Chatter in Apex. executeAnonymous always executes using the full permissions of the current user. For more information on executeAnonymous, see [Anonymous Blocks](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_anonymous_block.htm).