diff --git a/entity.api.php b/entity.api.php
index dff6cdc..f528f28 100644
--- a/entity.api.php
+++ b/entity.api.php
@@ -38,15 +38,24 @@
  *   additional keys are used by the entity CRUD API:
  *   - name: (optional) The key of the entity property containing the unique,
  *     machine readable name of the entity. If specified, this is used as
- *     uniform identifier of the entity, while the usual 'id' key is still
- *     required. If a name key is given, the name is used as identifier for all
- *     API functions like entity_load(), but the numeric id as specified by the
- *     'id' key is still used to refer to the entity internally, i.e. in the
- *     database.
- *     For exportable entities, it's strongly recommended to use a machine name
- *     here as those are more portable across systems.
+ *     identifier of the entity, while the usual 'id' key is still required and
+ *     may be used when modules deal with entities generically, or to refer to
+ *     the entity internally, i.e. in the database.
+ *     If a name key is given, the name is used as entity identifier for most
+ *     API functions and hooks. However note that for consistency all generic
+ *     entity hooks like hook_entity_load() are invoked with the entities keyed
+ *     by numeric id, while entity-type specific hooks like
+ *     hook_{entity_type}_load() are invoked with the entities keyed by name.
+ *     Also, just as entity_load_single() entity_load() may be called
+ *     with names passed as the $ids parameter, while the results of
+ *     entity_load() are always keyed by numeric id. Thus, it is suggested to
+ *     make use of entity_load_multiple_by_name() to implement entity-type
+ *     specific loading functions like {entity_type}_load_multiple(), as this
+ *     function returns the entities keyed by name.
+ *     For exportable entities, it is strongly recommended to make use of a
+ *     machine name as names are portable across systems.
  *   - module: (optional) A key for the module property used by the entity CRUD
- *     API to save the source module name for exportable entities, which are
+ *     API to save the source module name for exportable entities that have been
  *     provided in code. Defaults to 'module'.
  *   - status: (optional) The name of the entity property used by the entity
  *     CRUD API to save the exportable entity status using defined bit flags.
diff --git a/entity.module b/entity.module
index 432d469..96cb423 100644
--- a/entity.module
+++ b/entity.module
@@ -71,6 +71,57 @@ function entity_type_supports($entity_type, $op) {
 }
 
 /**
+ * A wrapper around entity_load() to load a single entity by name or numeric id.
+ *
+ * @todo: Re-name entity_load() to entity_load_multiple() in d8 core and this
+ * to entity_load().
+ *
+ * @param $entity_type
+ *   The entity type to load, e.g. node or user.
+ * @param $id
+ *   The entity id, either the numeric id or the entity name. In case the entity
+ *   type has specified a name key, both the numeric id and the name may be
+ *   passed.
+ *
+ * @return
+ *   The entity object, or FALSE.
+ *
+ * @see entity_load()
+ */
+function entity_load_single($entity_type, $id) {
+  $entities = entity_load($entity_type, array($id));
+  return reset($entities);
+}
+
+/**
+ * A wrapper around entity_load() to return entities keyed by name key if existing.
+ *
+ * @param $entity_type
+ *   The entity type to load, e.g. node or user.
+ * @param $names
+ *   An array of entity names or ids, or FALSE to load all entities.
+ * @param $conditions
+ *   (deprecated) An associative array of conditions on the base table, where
+ *   the keys are the database fields and the values are the values those
+ *   fields must have. Instead, it is preferable to use EntityFieldQuery to
+ *   retrieve a list of entity IDs loadable by this function.
+ *
+ * @return
+ *   An array of entity objects indexed by their names (or ids if the entity
+ *   type has no name key).
+ *
+ * @see entity_load()
+ */
+function entity_load_multiple_by_name($entity_type, $names = FALSE, $conditions = array()) {
+  $entities = entity_load($entity_type, $names, $conditions);
+  $info = entity_get_info($entity_type);
+  if (!isset($info['entity keys']['name'])) {
+    return $entities;
+  }
+  return entity_key_array_by_property($entities, $info['entity keys']['name']);
+}
+
+/**
  * Permanently save an entity.
  *
  * In case of failures, an exception is thrown.
@@ -127,7 +178,8 @@ function entity_delete($entity_type, $id) {
  * @param $entity_type
  *   The type of the entity.
  * @param $ids
- *   An array of uniform identifiers of the entities to delete.
+ *   An array of entity ids of the entities to delete. In case the entity makes
+ *   use of a name key, both the names or numeric ids may be passed.
  * @return
  *   FALSE if the given entity type isn't compatible to the CRUD API.
  */
@@ -251,11 +303,10 @@ function entity_build_content($entity_type, $entity, $view_mode = 'full', $langc
 }
 
 /**
- * Returns the entity identifier.
+ * Returns the entity identifier, i.e. the entities name or numeric id.
  *
- * Unlike entity_extract_ids() this function returns the uniform identifier,
- * thus if an exportable entity makes use of a name key, the name of the entity
- * is returned. Otherwise the usual numeric id is returned.
+ * Unlike entity_extract_ids() this function returns the name of the entity
+ * instead of the numeric id, in case the entity type has specified a name key.
  *
  * @param $entity_type
  *   The type of the entity.
@@ -276,19 +327,23 @@ function entity_id($entity_type, $entity) {
 /**
  * Generate an array for rendering the given entities.
  *
+ * Entities being viewed, are generally expected to be fully-loaded entity
+ * objects, thus have their name or id key set. However, it is possible to
+ * view a single entity without any id, e.g. for generating a preview during
+ * creation.
+ *
  * @param $entity_type
  *   The type of the entity.
  * @param $entities
- *   An array of entities to render, keyed by their ids. E.g. as returned from
- *   entity_load().
+ *   An array of entities to render.
  * @param $view_mode
  *   A view mode as used by this entity type, e.g. 'full', 'teaser'...
  * @param $langcode
  *   (optional) A language code to use for rendering. Defaults to the global
  *   content language of the current request.
  * @return
- *   The renderable array, or FALSE if there is no information how to view an
- *   entity.
+ *   The renderable array, key by name key if existing or by numeric id else.
+ *   If there is no information how to view an entity, FALSE is returned.
  */
 function entity_view($entity_type, $entities, $view_mode = 'full', $langcode = NULL) {
   $info = entity_get_info($entity_type);
@@ -298,6 +353,7 @@ function entity_view($entity_type, $entities, $view_mode = 'full', $langcode = N
   elseif (in_array('EntityAPIControllerInterface', class_implements($info['controller class']))) {
     return entity_get_controller($entity_type)->view($entities, $view_mode, $langcode);
   }
+  return FALSE;
 }
 
 /**
@@ -327,6 +383,27 @@ function entity_access($op, $entity_type, $entity = NULL, $account = NULL) {
 }
 
 /**
+ * Converts an array of entities to be keyed by the values of a given property.
+ *
+ * @param array $entities
+ *   The array of entities to convert.
+ * @param $property
+ *   The name of entity property, by which the array should be keyed. To get
+ *   reasonable results, the property has to have unique values.
+ *
+ * @return array
+ *   The same entities in the same order, but keyed by their $property values.
+ */
+function entity_key_array_by_property(array $entities, $property) {
+  $ret = array();
+  foreach ($entities as $entity) {
+    $key = isset($entity->$property) ? $entity->$property : NULL;
+    $ret[$key] = $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 +569,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_load_multiple_by_name($entity_type, array_keys($entities), array($keys['status'] => ENTITY_OVERRIDDEN));
     $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_load_multiple_by_name($entity_type, array_keys($entities), array($keys['status'] => ENTITY_CUSTOM));
     foreach ($existing_entities as $name => $entity) {
       $entity->{$keys['status']} |= ENTITY_OVERRIDDEN;
       $entity->{$keys['module']} = $entities[$name]->{$keys['module']};
@@ -524,8 +601,20 @@ function _entity_defaults_rebuild($entity_type) {
  * Implements hook_modules_enabled().
  */
 function entity_modules_enabled($modules) {
+  $built_types = variable_get('entity_defaults_built', array());
   if ($entity_types = _entity_modules_get_default_types($modules)) {
-    entity_defaults_rebuild($entity_types);
+    // Determining the entity types might have triggered rebuilding already, in
+    // which case we do not need to rebuild again. So we make sure to only
+    // add entity-types for rebuilding that were not marked for rebuilding
+    // *before our check* anyway.
+    foreach ($entity_types as $key => $type) {
+      if (!isset($built_types[$type])) {
+        unset($entity_types[$key]);
+      }
+    }
+    if ($entity_types) {
+      entity_defaults_rebuild($entity_types);
+    }
   }
 }
 
diff --git a/entity.test b/entity.test
index 09a2551..d01ee1b 100644
--- a/entity.test
+++ b/entity.test
@@ -106,19 +106,21 @@ class EntityAPITestCase extends DrupalWebTestCase {
   function testExportables() {
     module_enable(array('entity_feature'));
 
-    $types = entity_load('entity_test_type', array('test', 'test2'));
+    $types = entity_load_multiple_by_name('entity_test_type', array('test2', 'test'));
+
+    $this->assertEqual(array_keys($types), array('test2', 'test'), 'Entities have been loaded in the order as specified.');
     $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.');
 
     // Test using a condition, which has to be applied on the defaults.
-    $types = entity_load('entity_test_type', FALSE, array('label' => 'label'));
+    $types = entity_load_multiple_by_name('entity_test_type', FALSE, array('label' => 'label'));
     $this->assertEqual($types['test']->label, 'label', 'Condition to default type applied.');
 
     $types['test']->label = 'modified';
     $types['test']->save();
 
     // Ensure loading the changed entity works.
-    $types = entity_load('entity_test_type', FALSE, array('label' => 'modified'));
+    $types = entity_load_multiple_by_name('entity_test_type', FALSE, array('label' => 'modified'));
     $this->assertEqual($types['test']->label, 'modified', 'Modified type loaded.');
 
     // Clear the cache to simulate a new page load.
@@ -126,30 +128,30 @@ class EntityAPITestCase extends DrupalWebTestCase {
 
     // Test loading using a condition again, now they 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'));
+    $types = entity_load_multiple_by_name('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'));
+    $types = entity_load_multiple_by_name('entity_test_type', FALSE, array('label' => 'modified'));
     $this->assertEqual($types['test']->label, 'modified', 'Modified default type loaded by condition.');
 
-    $types = entity_load('entity_test_type', array('test', 'test2'));
+    $types = entity_load_multiple_by_name('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.');
 
     // Test rebuilding the defaults and make sure overridden entities stay.
     entity_defaults_rebuild();
-    $types = entity_load('entity_test_type', array('test', 'test2'));
+    $types = entity_load_multiple_by_name('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.');
 
     // Test reverting.
     $types['test']->delete();
-    $types = entity_load('entity_test_type', array('test', 'test2'));
+    $types = entity_load_multiple_by_name('entity_test_type', array('test', 'test2'));
     $this->assertEqual($types['test']->label, 'label', 'Entity has been reverted.');
 
     // Test loading an exportable by its numeric id.
-    $result = entity_load('entity_test_type', array($types['test']->id));
+    $result = entity_load_multiple_by_name('entity_test_type', array($types['test']->id));
     $this->assertTrue(isset($result['test']), 'Exportable entity loaded by the numeric id.');
 
     // Test exporting an entity to JSON.
@@ -174,6 +176,10 @@ class EntityAPITestCase extends DrupalWebTestCase {
     $this->assertTrue($_SESSION['entity_hook_test']['entity_insert'] == $insert, 'Hook entity_insert has been invoked.');
     $this->assertTrue($_SESSION['entity_hook_test']['entity_test_type_insert'] == $insert, 'Hook entity_test_type_insert has been invoked.');
 
+    // Load a default entity and make sure the rebuilt logic only ran once.
+    entity_load_single('entity_test_type', 'test');
+    $this->assertTrue(!isset($_SESSION['entity_hook_test']['entity_test_type_update']), '"Entity-test-type" defaults have been rebuilt only once.');
+
     // Add a new test entity in DB and make sure the hook is invoked too.
     $test3 = entity_create('entity_test_type', array(
       'name' => 'test3',
@@ -187,7 +193,7 @@ class EntityAPITestCase extends DrupalWebTestCase {
     $this->assertTrue($_SESSION['entity_hook_test']['entity_test_type_insert'] == $insert, 'Hook entity_test_type_insert has been invoked.');
 
     // Now override the 'test' entity and make sure it invokes the update hook.
-    $result = entity_load('entity_test_type', array('test'));
+    $result = entity_load_multiple_by_name('entity_test_type', array('test'));
     $result['test']->label = 'modified';
     $result['test']->save();
 
@@ -202,7 +208,7 @@ class EntityAPITestCase extends DrupalWebTestCase {
     $this->assertTrue($_SESSION['entity_hook_test']['entity_test_type_delete'] == $delete, 'Hook entity_test_type_deleted has been invoked.');
 
     // Now make sure 'test' is not overridden any more, but custom.
-    $result = entity_load('entity_test_type', array('test'));
+    $result = entity_load_multiple_by_name('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.');
 
@@ -219,7 +225,7 @@ class EntityAPITestCase extends DrupalWebTestCase {
    */
   function testChanges() {
     module_enable(array('entity_feature'));
-    $types = entity_load('entity_test_type');
+    $types = entity_load_multiple_by_name('entity_test_type');
 
     // Override the default entity, such it gets saved in the DB.
     $types['test']->label ='test_changes';
@@ -239,7 +245,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_load_multiple_by_name('entity_test_type');
     $this->assertEqual($types['test']->label, 'updated_presave', 'Static cache has been cleared.');
   }
 
@@ -933,7 +939,7 @@ class EntityMetadataIntegrationTestCase extends DrupalWebTestCase {
       if ($return === FALSE) {
         continue; // No support for deleting.
       }
-      $return = entity_load($entity_type, array($id));
+      $return = entity_load_single($entity_type, $id);
       $this->assertFalse($return, "$entity_type has been successfully deleted.");
     }
   }
diff --git a/includes/entity.controller.inc b/includes/entity.controller.inc
index 83fe55e..c66b1e7 100644
--- a/includes/entity.controller.inc
+++ b/includes/entity.controller.inc
@@ -106,7 +106,7 @@ interface EntityAPIControllerInterface extends DrupalEntityControllerInterface {
    *   (optional) A language code to use for rendering. Defaults to the global
    *   content language of the current request.
    * @return
-   *   The renderable array.
+   *   The renderable array, keyed by entity name or numeric id.
    */
   public function view($entities, $view_mode = 'full', $langcode = NULL);
 }
@@ -117,7 +117,7 @@ interface EntityAPIControllerInterface extends DrupalEntityControllerInterface {
  */
 class EntityAPIController extends DrupalDefaultEntityController implements EntityAPIControllerInterface {
 
-  protected $cacheComplete = FALSE;
+  protected $cacheComplete = FALSE, $entityCacheByName = array();
   protected $nameKey, $statusKey, $moduleKey, $bundleKey;
 
   /**
@@ -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;
       }
     }
 
@@ -254,7 +254,7 @@ class EntityAPIController extends DrupalDefaultEntityController implements Entit
       if (!empty($queried_entities) && !$revision_id) {
         $this->cacheSet($queried_entities);
 
-        // Remember we have cached all entities now.
+        // Remember if we have cached all entities now.
         if (!$conditions && $ids === FALSE) {
           $this->cacheComplete = TRUE;
         }
@@ -262,15 +262,42 @@ class EntityAPIController extends DrupalDefaultEntityController implements Entit
     }
     // Ensure that the returned array is ordered the same as the original
     // $ids array if this was passed in and remove any invalid ids.
-    if ($passed_ids && $passed_ids = array_intersect_key($passed_ids, $entities)) {
+    if ($passed_ids) {
+      if ($this->nameKey != $this->idKey && !is_numeric(key($passed_ids))) {
+        $entities = entity_key_array_by_property($entities, $this->nameKey);
+      }
+      $return = array();
       foreach ($passed_ids as $id => $value) {
-        $passed_ids[$id] = $entities[$id];
+        if (isset($entities[$id])) {
+          $return[$entities[$id]->{$this->idKey}] = $entities[$id];
+        }
       }
-      $entities = $passed_ids;
+      $entities = $return;
     }
     return $entities;
   }
 
+  /**
+   * Overridden.
+   * @see DrupalDefaultEntityController::cacheGet()
+   */
+  protected function cacheGet($ids, $conditions = array()) {
+    if (!empty($this->entityCache)) {
+      // First get the entities by ids, then apply the conditions.
+      if (!is_array($ids)) {
+        $entities = $this->entityCache;
+      }
+      elseif ($this->nameKey != $this->idKey && !is_numeric(reset($ids))) {
+        $entities = entity_key_array_by_property(array_intersect_key($this->entityCacheByName, array_flip($ids)), $this->idKey);
+      }
+      else {
+        $entities = array_intersect_key($this->entityCache, array_flip($ids));
+      }
+      return $this->applyConditions($entities, $conditions);
+    }
+    return array();
+  }
+
   protected function applyConditions($entities, $conditions = array()) {
     if ($conditions) {
       foreach ($entities as $key => $entity) {
@@ -285,37 +312,30 @@ 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.
+   * @see DrupalDefaultEntityController::cacheSet()
    */
-  protected function cacheGet($ids, $conditions = array()) {
-    if (!empty($this->entityCache)) {
-      // First get the entities by ids, then apply the conditions.
-      $entities = is_array($ids) ? array_intersect_key($this->entityCache, array_flip($ids)) : $this->entityCache;
-      return $this->applyConditions($entities, $conditions);
+  protected function cacheSet($entities) {
+    $this->entityCache += $entities;
+    if ($this->nameKey != $this->idKey) {
+      $this->entityCacheByName += entity_key_array_by_property($entities, $this->nameKey);
     }
-    return array();
   }
 
   /**
    * Overridden.
    * @see DrupalDefaultEntityController::attachLoad()
    *
-   * Fixed to make attaching fields to entities having a name key work.
+   * Changed to call type-specific hook with the entities keyed by name if they
+   * have one.
    */
   protected function attachLoad(&$queried_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);
+        field_attach_load_revision($this->entityType, $queried_entities);
       }
       else {
-        field_attach_load($this->entityType, $entities);
+        field_attach_load($this->entityType, $queried_entities);
       }
     }
 
@@ -327,29 +347,34 @@ class EntityAPIController extends DrupalDefaultEntityController implements Entit
     // 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($queried_entities, $this->nameKey);
+    }
+    else {
+      $entities_by_name = $queried_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.
-   */
-  protected function getEntitiesKeyedByNumericID($entities) {
-    if ($this->nameKey != $this->idKey) {
-      $result = array();
-      foreach ($entities as $entity) {
-        $result[$entity->{$this->idKey}] = $entity;
-      }
-      return $result;
-    }
-    return $entities;
-  }
-
   public function resetCache(array $ids = NULL) {
     $this->cacheComplete = FALSE;
-    parent::resetCache($ids);
+    if (isset($ids)) {
+      foreach ($ids as $id) {
+        if (isset($this->entityCache[$id])) {
+          unset($this->entityCacheByName[$this->entityCache[$id]->{$this->nameKey}]);
+          unset($this->entityCache[$id]);
+        }
+      }
+    }
+    else {
+      $this->entityCache = array();
+      $this->entityCacheByName = array();
+    }
   }
 
   /**
@@ -404,8 +429,10 @@ class EntityAPIController extends DrupalDefaultEntityController implements Entit
     $transaction = isset($transaction) ? $transaction : db_transaction();
 
     try {
+      $ids = array_keys($entities);
+
       db_delete($this->entityInfo['base table'])
-        ->condition($this->nameKey, array_keys($entities), 'IN')
+        ->condition($this->idKey, $ids, 'IN')
         ->execute();
       // Reset the cache as soon as the changes have been applied.
       $this->resetCache($ids);
@@ -458,7 +485,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 {
@@ -553,20 +580,22 @@ class EntityAPIController extends DrupalDefaultEntityController implements Entit
    * Implements EntityAPIControllerInterface.
    */
   public function view($entities, $view_mode = 'full', $langcode = NULL) {
+    // For Field API and entity_prepare_view, the entities have to be keyed by
+    // (numeric) id.
+    $entities = entity_key_array_by_property($entities, $this->idKey);
     if (!empty($this->entityInfo['fieldable'])) {
-      // Field API assumes queried entities are keyed by the idkey, thus
-      // adapt the array accordingly for it.
-      field_attach_prepare_view($this->entityType, $this->getEntitiesKeyedByNumericID($entities), $view_mode);
+      field_attach_prepare_view($this->entityType, $entities, $view_mode);
     }
     entity_prepare_view($this->entityType, $entities);
     $langcode = isset($langcode) ? $langcode : $GLOBALS['language_content']->language;
 
     $view = array();
-    foreach ($entities as $key => $entity) {
+    foreach ($entities as $entity) {
       $build = entity_build_content($this->entityType, $entity, $view_mode, $langcode);
       $build += array(
         // If the entity type provides an implementation, use this instead the
         // generic one.
+        // @see template_preprocess_entity()
         '#theme' => 'entity',
         '#entity_type' => $this->entityType,
         '#entity' => $entity,
@@ -575,9 +604,9 @@ class EntityAPIController extends DrupalDefaultEntityController implements Entit
       );
       // Allow modules to modify the structured entity.
       drupal_alter(array($this->entityType . '_view', 'entity_view'), $build, $this->entityType);
+      $key = isset($entity->{$this->nameKey}) ? $entity->{$this->nameKey} : NULL;
       $view[$this->entityType][$key] = $build;
     }
     return $view;
   }
-
 }
diff --git a/includes/entity.inc b/includes/entity.inc
index 89903cd..5bbbaf7 100644
--- a/includes/entity.inc
+++ b/includes/entity.inc
@@ -48,21 +48,21 @@ class Entity {
   /**
    * Returns the internal, numeric identifier.
    *
-   * For exportable entities, this differs to the uniform identifier returned
-   * by Entity::identifier(). The internal identifier is supposed to be only
-   * used internally to refer to an entity, i.e. in the database. If unsure, use
-   * Entity:identifier().
+   * Returns the numeric identifier, even if the entity type has specified a
+   * name key. In the latter case, the numeric identifier is supposed to be used
+   * when dealing generically with entities or internally to refer to an entity,
+   * i.e. in a relational database. If unsure, use Entity:identifier().
    */
   public function internalIdentifier() {
     return isset($this->{$this->idKey}) ? $this->{$this->idKey} : NULL;
   }
 
   /**
-   * Returns the unified identifer.
+   * Returns the entity identifier, i.e. the entities name or numeric id.
    *
    * @return
-   *   The identifier of the entity. For exportable entities, this is their
-   *   machine readable name.
+   *   The identifier of the entity. If the entity type makes use of a name key,
+   *   the name is returned, else the numeric id.
    *
    * @see entity_id()
    */
@@ -188,7 +188,7 @@ class Entity {
    * @see entity_view()
    */
   public function view($view_mode = 'full', $langcode = NULL) {
-    return entity_get_controller($this->entityType)->view(array($this->identifier() => $this), $view_mode, $langcode);
+    return entity_get_controller($this->entityType)->view(array($this), $view_mode, $langcode);
   }
 
   /**
diff --git a/tests/entity_test.module b/tests/entity_test.module
index c1cf2d5..77baf72 100644
--- a/tests/entity_test.module
+++ b/tests/entity_test.module
@@ -66,11 +66,8 @@ function entity_test_entity_info_alter(&$entity_info) {
  *   If set, the type with the given name is returned.
  */
 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;
+  $types = entity_load_multiple_by_name('entity_test_type', isset($name) ? array($name) : FALSE);
+  return isset($name) ? reset($types) : $types;
 }
 
 /**
