diff --git a/core/includes/entity.api.php b/core/includes/entity.api.php
index e9fb855..2aa96a9 100644
--- a/core/includes/entity.api.php
+++ b/core/includes/entity.api.php
@@ -141,6 +141,12 @@
  *       by default (e.g. right after the module exposing the view mode is
  *       enabled), but administrators can later use the Field UI to apply custom
  *       display settings specific to the view mode.
+ *   - menu base path: The base menu router path to which the administration
+ *     user interface will be attached. Defaults to ENTITY_TYPE/%ENTITY_TYPE.
+ *   - menu view path: The menu router path to be used to view the entity.
+ *     Defaults to the base path.
+ *   - menu edit path: The menu router path to be used to edit the entity.
+ *     Defaults to "$base_path/edit".
  *
  * @see entity_load()
  * @see entity_load_multiple()
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index be36bc6..ab0f17d 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -126,6 +126,7 @@ function comment_entity_info() {
           'custom settings' => FALSE,
         ),
       ),
+      'translation controller class' => 'Drupal\comment\CommentTranslationController',
       'static cache' => FALSE,
     ),
   );
@@ -151,14 +152,6 @@ function comment_entity_info() {
     );
   }
 
-  // @todo Remove this check once field translation handlers are dropped as we
-  // will not need to check if Entity Translation is actually enabled.
-  if (module_exists('translation_entity')) {
-    $return['comment']['translation']['translation_entity'] = array(
-      'class' => 'Drupal\comment\CommentTranslationController',
-    );
-  }
-
   return $return;
 }
 
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 5517818..ef0845b 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -232,6 +232,7 @@ function node_entity_info() {
           'custom settings' => FALSE,
         ),
       ),
+      'translation controller class' => 'Drupal\node\NodeTranslationController',
     ),
   );
 
@@ -240,14 +241,6 @@ function node_entity_info() {
     $return['node']['translation']['node'] = TRUE;
   }
 
-  // @todo Remove this check once field translation handlers are dropped as we
-  // will not need to check if Entity Translation is actually enabled.
-  if (module_exists('translation_entity')) {
-    $return['node']['translation']['translation_entity'] = array(
-      'class' => 'Drupal\node\NodeTranslationController',
-    );
-  }
-
   // Search integration is provided by node.module, so search-related
   // view modes for nodes are defined here and not in search.module.
   if (module_exists('search')) {
diff --git a/core/modules/system/tests/modules/entity_test/entity_test.module b/core/modules/system/tests/modules/entity_test/entity_test.module
index 57704d5..0b5f415 100644
--- a/core/modules/system/tests/modules/entity_test/entity_test.module
+++ b/core/modules/system/tests/modules/entity_test/entity_test.module
@@ -27,11 +27,7 @@ function entity_test_entity_info() {
       'uuid' => 'uuid',
     ),
     'menu base path' => 'entity-test/manage/%entity_test',
-    'translation' => array(
-      'translation_entity' => array(
-        'class' => 'Drupal\entity_test\EntityTestTranslationController',
-      ),
-    ),
+    'translation controller class' => 'Drupal\entity_test\EntityTestTranslationController',
   );
 
   // Optionally specify a translation handler for testing translations.
diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module
index b350142..9008440 100644
--- a/core/modules/taxonomy/taxonomy.module
+++ b/core/modules/taxonomy/taxonomy.module
@@ -138,6 +138,8 @@ function taxonomy_entity_info() {
           'custom settings' => FALSE,
         ),
       ),
+      'menu base path' => 'taxonomy/term/%taxonomy_term',
+      'translation controller class' => 'Drupal\taxonomy\TermTranslationController',
     ),
   );
 
@@ -153,15 +155,6 @@ function taxonomy_entity_info() {
     );
   }
 
-  // @todo Remove this check once field translation handlers are dropped as we
-  // will not need to check if Entity Translation is actually enabled.
-  if (module_exists('translation_entity')) {
-    $return['taxonomy_term']['menu base path'] = 'taxonomy/term/%taxonomy_term';
-    $return['taxonomy_term']['translation']['translation_entity'] = array(
-      'class' => 'Drupal\taxonomy\TermTranslationController',
-    );
-  }
-
   $return['taxonomy_vocabulary'] = array(
     'label' => t('Taxonomy vocabulary'),
     'entity class' => 'Drupal\taxonomy\Vocabulary',
diff --git a/core/modules/translation_entity/lib/Drupal/translation_entity/EntityTranslationControllerInterface.php b/core/modules/translation_entity/lib/Drupal/translation_entity/EntityTranslationControllerInterface.php
index e01e3c4..fd597d8 100644
--- a/core/modules/translation_entity/lib/Drupal/translation_entity/EntityTranslationControllerInterface.php
+++ b/core/modules/translation_entity/lib/Drupal/translation_entity/EntityTranslationControllerInterface.php
@@ -22,6 +22,9 @@
    *
    * @param Drupal\Core\Entity\EntityInterface $entity
    *   The entity to the path should refer to.
+   *
+   * @return string
+   *   The entity base path.
    */
   public function getBasePath(EntityInterface $entity);
 
@@ -30,6 +33,9 @@ public function getBasePath(EntityInterface $entity);
    *
    * @param Drupal\Core\Entity\EntityInterface $entity
    *   The entity to the path should refer to.
+   *
+   * @return string
+   *   The entity edit path.
    */
   public function getEditPath(EntityInterface $entity);
 
@@ -38,6 +44,10 @@ public function getEditPath(EntityInterface $entity);
    *
    * @param Drupal\Core\Entity\EntityInterface $entity
    *   The entity to the path should refer to.
+   *
+   *
+   * @return string
+   *   The entity view path.
    */
   public function getViewPath(EntityInterface $entity);
 
@@ -77,11 +87,14 @@ public function getTranslationAccess(EntityInterface $entity, $langcode);
    *
    * @param array $form_state
    *   The form state array.
+   *
+   * @return string
+   *   The source language code.
    */
   public function getSourceLangcode(array $form_state);
 
   /**
-   * Remove the translation values from the given entity.
+   * Removes the translation values from the given entity.
    *
    * @param Drupal\Core\Entity\EntityInterface $entity
    *   The entity whose values should be removed.
diff --git a/core/modules/translation_entity/translation_entity.api.php b/core/modules/translation_entity/translation_entity.api.php
new file mode 100644
index 0000000..654b6a0
--- /dev/null
+++ b/core/modules/translation_entity/translation_entity.api.php
@@ -0,0 +1,55 @@
+<?php
+
+/**
+ * @file
+ * API documentation for the Entity Translation module.
+ */
+
+/**
+ * Allows modules to define their own translation info.
+ *
+ * Entity Translation relies on the entity info to provide its translation
+ * features. See the documentation of hook_entity_info() in the Entity API
+ * documentation for more details on all the entity info keys that may be
+ * defined.
+ *
+ * To make Entity Translation automatically support an entity type some keys
+ * may need to be defined, but none of them is required unless the entity path
+ * is different from ENTITY_TYPE/%ENTITY_TYPE (e.g. taxonomy/term/1), in which
+ * case the 'menu base path' key must be defined. The 'menu base path' key is
+ * used to determine the view and edit paths, if they follow the default path
+ * patterns and to reliably alter menu information to provide the translation
+ * UI. If the entity path matches the default pattern above, and there is no
+ * need for an entity-specific translation controller class, Entity Translation
+ * will provide built-in support for the entity.
+ *
+ * An alternative translation controller class can be defined through:
+ * - translation controller class: The name of the translation controller class,
+ *   that should be used to handle the translation process. Defaults to
+ *   Drupal\translation_entity\EntityTranslationController'. This class must
+ *   implement Drupal\translation_entity\EntityTranslationControllerInterface.
+ *
+ * The entity translation info is an associative array that has to match the
+ * following structure. Three nested sub-arrays keyed respectively by entity
+ * type, the 'translation' key and the 'entity_translation' key: the second one
+ * is the key defined by the core entity system while the third one registers
+ * Entity Tanslation as a field translation handler. Elements:
+ * - access callback: The access callback for the translation pages. Defaults to
+ *   'entity_translation_translate_access'.
+ * - access arguments: The access arguments for the translation pages. Defaults
+ *   to 'array($entity_position)'.
+ */
+function hook_entity_info() {
+  $info['custom_entity'] = array(
+    // ...
+    'menu base path' => 'custom/path/%custom_entity',
+    'translation controller class' => 'Drupal\custom_module\CustomEntityTranslationController',
+    'translation' => array(
+      'entity_translation' => array(
+        'access callback' => 'custom_entity_translate_access',
+        'access arguments' => array(2),
+      ),
+    ),
+  );
+  return $info;
+}
diff --git a/core/modules/translation_entity/translation_entity.module b/core/modules/translation_entity/translation_entity.module
index 6f0fba5..974e653 100644
--- a/core/modules/translation_entity/translation_entity.module
+++ b/core/modules/translation_entity/translation_entity.module
@@ -24,35 +24,35 @@ function translation_entity_entity_info_alter(&$entity_info) {
   $edit_form_info = array();
 
   // Provide defaults for translation info.
-  foreach ($entity_info as $entity_type => $info) {
-    if (!isset($entity_info[$entity_type]['translation']['translation_entity'])) {
-      $entity_info[$entity_type]['translation']['translation_entity'] = array();
+  foreach ($entity_info as $entity_type => &$info) {
+    if (!isset($info['translation']['translation_entity'])) {
+      $info['translation']['translation_entity'] = array();
     }
 
     // Every fieldable entity type must have a translation controller class, no
     // matter if it is enabled for translation or not. As a matter of fact we
     // might need it to correctly switch field translatability when a field is
     // shared accross different entities.
-    $entity_info[$entity_type]['translation']['translation_entity'] += array('class' => 'Drupal\translation_entity\EntityTranslationController');
+    $info += array('translation controller class' => 'Drupal\translation_entity\EntityTranslationController');
 
     if (translation_entity_enabled($entity_type, NULL, TRUE)) {
-      // If no menu base path is provided we default to the common "node/%node"
-      // pattern.
-      if (!isset($entity_info[$entity_type]['menu base path'])) {
+      // If no menu base path is provided we default to the usual
+      // "entity_type/%entity_type" pattern.
+      if (!isset($info['menu base path'])) {
         $path = "$entity_type/%$entity_type";
-        $entity_info[$entity_type]['menu base path'] = $path;
+        $info['menu base path'] = $path;
       }
 
-      $path = $entity_info[$entity_type]['menu base path'];
+      $path = $info['menu base path'];
 
-      $entity_info[$entity_type] += array(
+      $info += array(
         'menu view path' => $path,
         'menu edit path' => "$path/edit",
         'menu path wildcard' => "%$entity_type",
       );
 
       $entity_position = count(explode('/', $path)) - 1;
-      $entity_info[$entity_type]['translation']['translation_entity'] += array(
+      $info['translation']['translation_entity'] += array(
         'access callback' => 'translation_entity_translate_access',
         'access arguments' => array($entity_position),
       );
@@ -292,8 +292,7 @@ function translation_entity_enabled($entity_type, $bundle = NULL, $skip_handler
 function translation_entity_controller($entity_type) {
   $entity_info = entity_get_info($entity_type);
   // @todo Throw an exception if the key is missing.
-  $class = $entity_info['translation']['translation_entity']['class'];
-  return new $class($entity_type, $entity_info);
+  return new $entity_info['translation controller class']($entity_type, $entity_info);
 }
 
 /**
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index dec75fe..1d2958f 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -178,17 +178,10 @@ function user_entity_info() {
           'custom settings' => FALSE,
         ),
       ),
+      'translation controller class' => 'Drupal\user\ProfileTranslationController',
     ),
   );
 
-  // @todo Remove this check once field translation handlers are dropped as we
-  // will not need to check if Entity Translation is actually enabled.
-  if (module_exists('translation_entity')) {
-    $return['user']['translation']['translation_entity'] = array(
-      'class' => 'Drupal\user\ProfileTranslationController',
-    );
-  }
-
   return $return;
 }
 
