diff --git a/entity.module b/entity.module
index 432d469..74cd2e6 100644
--- a/entity.module
+++ b/entity.module
@@ -327,6 +327,26 @@ function entity_access($op, $entity_type, $entity = NULL, $account = NULL) {
 }
 
 /**
+ * Converts an array of entities to be keyed by the given property.
+ *
+ * @param array $entities
+ *   The array of entities to convert.
+ *
+ * @return array
+ *   The same entities in the same order, but keyed by their $property values.
+ *   Entities not having the specified property will be excluded.
+ */
+function entity_key_array_by_property(array $entities, $property) {
+  $ret = array();
+  foreach ($entities as $entity) {
+    if (isset($entity->$property)) {
+      $ret[$entity->$property] = $entity;
+    }
+  }
+  return $ret;
+}
+
+/**
  * Returns an array of entity info for the entity types provided via the entity CRUD API.
  */
 function entity_crud_get_info() {
@@ -492,11 +512,11 @@ function _entity_defaults_rebuild($entity_type) {
     drupal_alter($hook, $entities);
 
     // Remove defaults which are already overridden.
-    $overridden_entities = entity_load($entity_type, array_keys($entities), array($keys['status'] => ENTITY_OVERRIDDEN));
+    $overridden_entities = entity_key_array_by_property(entity_load($entity_type, array_keys($entities), array($keys['status'] => ENTITY_OVERRIDDEN)), $keys['name']);
     $entities = array_diff_key($entities, $overridden_entities);
 
     // Determine already existing, custom entities and mark them as overridden.
-    $existing_entities = entity_load($entity_type, array_keys($entities), array($keys['status'] => ENTITY_CUSTOM));
+    $existing_entities = entity_key_array_by_property(entity_load($entity_type, array_keys($entities), array($keys['status'] => ENTITY_CUSTOM)), $keys['name']);
     foreach ($existing_entities as $name => $entity) {
       $entity->{$keys['status']} |= ENTITY_OVERRIDDEN;
       $entity->{$keys['module']} = $entities[$name]->{$keys['module']};
diff --git a/entity.test b/entity.test
index 09a2551..2d0a61a 100644
--- a/entity.test
+++ b/entity.test
@@ -107,57 +107,62 @@ class EntityAPITestCase extends DrupalWebTestCase {
     module_enable(array('entity_feature'));
 
     $types = entity_load('entity_test_type', array('test', 'test2'));
-    $this->assertEqual($types['test']->label, 'label', 'Default type loaded.');
-    $this->assertTrue($types['test']->status & ENTITY_IN_CODE && !($types['test']->status & ENTITY_CUSTOM), 'Default type status is correct.');
+    $type = reset($types);
+    $id = $type->id;
+    $this->assertEqual($id, key($types), 'Types loaded keyed by id.');
+    $this->assertEqual($type->label, 'label', 'Default type loaded.');
+    $this->assertTrue($type->status & ENTITY_IN_CODE && !($type->status & ENTITY_CUSTOM), 'Default type status is correct.');
 
     // Test using a condition, which has to be applied on the defaults.
     $types = entity_load('entity_test_type', FALSE, array('label' => 'label'));
-    $this->assertEqual($types['test']->label, 'label', 'Condition to default type applied.');
+    $this->assertEqual($types[$id]->label, 'label', 'Condition to default type applied.');
 
-    $types['test']->label = 'modified';
-    $types['test']->save();
+    $types[$id]->label = 'modified';
+    $types[$id]->save();
 
     // Ensure loading the changed entity works.
     $types = entity_load('entity_test_type', FALSE, array('label' => 'modified'));
-    $this->assertEqual($types['test']->label, 'modified', 'Modified type loaded.');
+    $this->assertEqual($types[$id]->label, 'modified', 'Modified type loaded.');
 
     // Clear the cache to simulate a new page load.
     entity_get_controller('entity_test_type')->resetCache();
 
-    // Test loading using a condition again, now they default may not appear any
+    // Test loading using a condition again, now the default may not appear any
     // more as it's overridden by an entity with another label.
     $types = entity_load('entity_test_type', FALSE, array('label' => 'label'));
     $this->assertTrue(empty($types), 'Conditions are applied to the overridden entity only.');
 
     // But the overridden entity has to appear with another condition.
     $types = entity_load('entity_test_type', FALSE, array('label' => 'modified'));
-    $this->assertEqual($types['test']->label, 'modified', 'Modified default type loaded by condition.');
+    $this->assertEqual($types[$id]->label, 'modified', 'Modified default type loaded by condition.');
 
     $types = entity_load('entity_test_type', array('test', 'test2'));
-    $this->assertEqual($types['test']->label, 'modified', 'Modified default type loaded by id.');
-    $this->assertTrue(entity_has_status('entity_test_type', $types['test'], ENTITY_OVERRIDDEN), 'Status of overridden type is correct.');
+    $this->assertEqual($types[$id]->label, 'modified', 'Modified default type loaded by id.');
+    $this->assertTrue(entity_has_status('entity_test_type', $types[$id], ENTITY_OVERRIDDEN), 'Status of overridden type is correct.');
 
     // Test rebuilding the defaults and make sure overridden entities stay.
     entity_defaults_rebuild();
     $types = entity_load('entity_test_type', array('test', 'test2'));
-    $this->assertEqual($types['test']->label, 'modified', 'Overridden entity is still overridden.');
-    $this->assertTrue(entity_has_status('entity_test_type', $types['test'], ENTITY_OVERRIDDEN), 'Status of overridden type is correct.');
+    $this->assertEqual($types[$id]->label, 'modified', 'Overridden entity is still overridden.');
+    $this->assertTrue(entity_has_status('entity_test_type', $types[$id], ENTITY_OVERRIDDEN), 'Status of overridden type is correct.');
 
     // Test reverting.
-    $types['test']->delete();
-    $types = entity_load('entity_test_type', array('test', 'test2'));
-    $this->assertEqual($types['test']->label, 'label', 'Entity has been reverted.');
+    $types[$id]->delete();
+    $types = entity_load('entity_test_type', array('test'));
+    $type = reset($types);
+    $id = $type->id;
+    $this->assertEqual($type->label, 'label', 'Entity has been reverted.');
 
     // Test loading an exportable by its numeric id.
-    $result = entity_load('entity_test_type', array($types['test']->id));
-    $this->assertTrue(isset($result['test']), 'Exportable entity loaded by the numeric id.');
+    $result = entity_load('entity_test_type', array($id));
+    $this->assertTrue(isset($result[$id]), 'Exportable entity loaded by the numeric id.');
 
     // Test exporting an entity to JSON.
-    $serialized_string = $types['test']->export();
+    $serialized_string = $type->export();
     $data = drupal_json_decode($serialized_string);
     $this->assertNotNull($data, 'Exported entity is valid JSON.');
     $import = entity_import('entity_test_type', $serialized_string);
-    $this->assertTrue(get_class($import) == get_class($types['test']) && $types['test']->label == $import->label, 'Successfully exported entity to code.');
+    $this->assertTrue(get_class($import) == get_class($types[$id]) && $types[$id]->label == $import->label, 'Successfully exported entity to code.');
     $this->assertTrue(!isset($import->status), 'Exportable status has not been exported to code.');
   }
 
@@ -188,8 +193,9 @@ class EntityAPITestCase extends DrupalWebTestCase {
 
     // Now override the 'test' entity and make sure it invokes the update hook.
     $result = entity_load('entity_test_type', array('test'));
-    $result['test']->label = 'modified';
-    $result['test']->save();
+    $result = reset($result);
+    $result->label = 'modified';
+    $result->save();
 
     $this->assertTrue($_SESSION['entity_hook_test']['entity_update'] == array('test'), 'Hook entity_update has been invoked.');
     $this->assertTrue($_SESSION['entity_hook_test']['entity_test_type_update'] == array('test'), 'Hook entity_test_type_update has been invoked.');
@@ -203,8 +209,9 @@ class EntityAPITestCase extends DrupalWebTestCase {
 
     // Now make sure 'test' is not overridden any more, but custom.
     $result = entity_load('entity_test_type', array('test'));
-    $this->assertTrue(!$result['test']->hasStatus(ENTITY_OVERRIDDEN), 'Entity is not marked as overridden any more.');
-    $this->assertTrue(entity_has_status('entity_test_type', $result['test'], ENTITY_CUSTOM), 'Entity is marked as custom.');
+    $result = reset($result);
+    $this->assertTrue(!$result->hasStatus(ENTITY_OVERRIDDEN), 'Entity is not marked as overridden any more.');
+    $this->assertTrue(entity_has_status('entity_test_type', $result, ENTITY_CUSTOM), 'Entity is marked as custom.');
 
     // Test deleting the remaining entities from DB.
     entity_delete_multiple('entity_test_type', array('test', 'test3'));
@@ -219,7 +226,7 @@ class EntityAPITestCase extends DrupalWebTestCase {
    */
   function testChanges() {
     module_enable(array('entity_feature'));
-    $types = entity_load('entity_test_type');
+    $types = entity_key_array_by_property(entity_load('entity_test_type'), 'name');
 
     // Override the default entity, such it gets saved in the DB.
     $types['test']->label ='test_changes';
@@ -239,7 +246,7 @@ class EntityAPITestCase extends DrupalWebTestCase {
     $this->assertEqual($types['test']->label, 'updated_presave_update', 'Changes have been determined.');
 
     // Test the static load cache to be cleared.
-    $types = entity_load('entity_test_type');
+    $types = entity_key_array_by_property(entity_load('entity_test_type'), 'name');
     $this->assertEqual($types['test']->label, 'updated_presave', 'Static cache has been cleared.');
   }
 
diff --git a/includes/entity.controller.inc b/includes/entity.controller.inc
index 83fe55e..55cb098 100644
--- a/includes/entity.controller.inc
+++ b/includes/entity.controller.inc
@@ -217,7 +217,7 @@ class EntityAPIController extends DrupalDefaultEntityController implements Entit
       $queried_entities = array();
       foreach ($this->query($ids, $conditions, $revision_id) as $record) {
         // Skip entities already retrieved from cache.
-        if (isset($entities[$record->{$this->nameKey}])) {
+        if (isset($entities[$record->{$this->idKey}])) {
           continue;
         }
 
@@ -237,7 +237,7 @@ class EntityAPIController extends DrupalDefaultEntityController implements Entit
           }
         }
 
-        $queried_entities[$record->{$this->nameKey}] = $record;
+        $queried_entities[$record->{$this->idKey}] = $record;
       }
     }
 
@@ -286,9 +286,6 @@ class EntityAPIController extends DrupalDefaultEntityController implements Entit
   /**
    * Overridden.
    * @see includes/DrupalDefaultEntityController#cacheGet($ids, $conditions)
-   *
-   * If there is nameKey given, we index our entities by this key. This
-   * overrides cacheGet() to respect that when applying $conditions.
    */
   protected function cacheGet($ids, $conditions = array()) {
     if (!empty($this->entityCache)) {
@@ -303,14 +300,12 @@ class EntityAPIController extends DrupalDefaultEntityController implements Entit
    * Overridden.
    * @see DrupalDefaultEntityController::attachLoad()
    *
-   * Fixed to make attaching fields to entities having a name key work.
+   * Fixed to call type-specific hook with the entities keyed by name, if they
+   * have one.
    */
-  protected function attachLoad(&$queried_entities, $revision_id = FALSE) {
+  protected function attachLoad(&$entities, $revision_id = FALSE) {
     // Attach fields.
     if ($this->entityInfo['fieldable']) {
-      // Field API assumes queried entities are keyed by the idkey, thus
-      // adapt the array accordingly for it.
-      $entities = $this->getEntitiesKeyedByNumericID($queried_entities);
       if ($revision_id) {
         field_attach_load_revision($this->entityType, $entities);
       }
@@ -322,19 +317,27 @@ class EntityAPIController extends DrupalDefaultEntityController implements Entit
     // Call hook_entity_load().
     foreach (module_implements('entity_load') as $module) {
       $function = $module . '_entity_load';
-      $function($queried_entities, $this->entityType);
+      $function($entities, $this->entityType);
     }
     // Call hook_TYPE_load(). The first argument for hook_TYPE_load() are
     // always the queried entities, followed by additional arguments set in
     // $this->hookLoadArguments.
-    $args = array_merge(array($queried_entities), $this->hookLoadArguments);
+    // For entities with a name key, pass the entities keyed by name to the
+    // specific load hook.
+    if ($this->nameKey != $this->idKey) {
+      $entities_by_name = entity_key_array_by_property($entities, $this->nameKey);
+    }
+    else {
+      $entities_by_name = $entities;
+    }
+    $args = array_merge(array($entities_by_name), $this->hookLoadArguments);
     foreach (module_implements($this->entityInfo['load hook']) as $module) {
       call_user_func_array($module . '_' . $this->entityInfo['load hook'], $args);
     }
   }
 
   /**
-   * Converts an array of entities in an array of entities keyed by numeric id, i.e. by id key.
+   * Converts an array of entities to an array of entities keyed by numeric id, i.e. by id key.
    */
   protected function getEntitiesKeyedByNumericID($entities) {
     if ($this->nameKey != $this->idKey) {
@@ -405,7 +408,7 @@ class EntityAPIController extends DrupalDefaultEntityController implements Entit
 
     try {
       db_delete($this->entityInfo['base table'])
-        ->condition($this->nameKey, array_keys($entities), 'IN')
+        ->condition($this->idKey, array_keys($entities), 'IN')
         ->execute();
       // Reset the cache as soon as the changes have been applied.
       $this->resetCache($ids);
@@ -458,7 +461,7 @@ class EntityAPIController extends DrupalDefaultEntityController implements Entit
 
       if (!empty($entity->{$this->idKey}) && empty($entity->is_new)) {
         $return = drupal_write_record($this->entityInfo['base table'], $entity, $this->idKey);
-        $this->resetCache(array($entity->{$this->nameKey}));
+        $this->resetCache(array($entity->{$this->idKey}));
         $this->invoke('update', $entity);
       }
       else {
@@ -556,6 +559,8 @@ class EntityAPIController extends DrupalDefaultEntityController implements Entit
     if (!empty($this->entityInfo['fieldable'])) {
       // Field API assumes queried entities are keyed by the idkey, thus
       // adapt the array accordingly for it.
+      // @todo This assumes $entities is keyed by name, not id. Does this still
+      //   apply?
       field_attach_prepare_view($this->entityType, $this->getEntitiesKeyedByNumericID($entities), $view_mode);
     }
     entity_prepare_view($this->entityType, $entities);
diff --git a/tests/entity_test.module b/tests/entity_test.module
index c1cf2d5..8827dea 100644
--- a/tests/entity_test.module
+++ b/tests/entity_test.module
@@ -68,7 +68,7 @@ function entity_test_entity_info_alter(&$entity_info) {
 function entity_test_get_types($name = NULL) {
   $types = entity_load('entity_test_type', isset($name) ? array($name) : FALSE);
   if (isset($name)) {
-    return isset($types[$name]) ? $types[$name] : FALSE;
+    return $types ? reset($types) : FALSE;
   }
   return $types;
 }
