diff --git a/language_hierarchy.module b/language_hierarchy.module
index b3fcd7c..aac93c7 100644
--- a/language_hierarchy.module
+++ b/language_hierarchy.module
@@ -1,6 +1,22 @@
 <?php
 
 /**
+ * Implements hook_module_implements_alter().
+ */
+function language_hierarchy_module_implements_alter(&$implementations, $hook) {
+  switch ($hook) {
+    case 'field_language_alter':
+      // language_hierarchy_field_language_alter() must run after
+      // entity_translation_field_language_alter() and
+      // locale_field_language_alter().
+      $group = $implementations['language_hierarchy'];
+      unset($implementations['language_hierarchy']);
+      $implementations['language_hierarchy'] = $group;
+      break;
+  }
+}
+
+/**
  * Implements hook_language_init().
  */
 function language_hierarchy_language_init() {
@@ -24,6 +40,11 @@ function language_hierarchy_permission() {
       'title' => t('Always fallback to default language'),
       'description' => t('Always include default language in fallback chain.'),
     ),
+    'use entity labels outside fallback chain' => array(
+      'title' => t('Use entity labels outside fallback chain if necessary'),
+      'description' => t('Allow fallbacks outside the fallback chain for entity labels such as node titles if there is no valid fallback within the current chain.'),
+      'restrict access' => TRUE,
+    ),
   );
 }
 
@@ -502,6 +523,112 @@ function language_hierarchy_language_fallback_candidates_alter(array &$fallback_
 }
 
 /**
+ * Implements hook_field_language_alter().
+ *
+ * Language hierarchy enforces that languages only fallback to their parent
+ * languages, whereas Drupal core would allow all languages to be fallbacks.
+ * Title replacement fields are a special case, since we may want to show a
+ * title (e.g. to admins) even if there are no translations in a parent language
+ * so all languages are allowed as fallbacks for those. We give primacy to the
+ * entity's own language first, then parent languages ahead of cousin languages.
+ * Since this may mean content is exposed that would not normally be accessible
+ * to users, a permission is used to toggle this functionality.
+ */
+function language_hierarchy_field_language_alter(&$display_language, $context) {
+  $entity_type = $context['entity_type'];
+  $entity_info = entity_get_info($entity_type);
+  if (isset($entity_info['field replacement']) && user_access('use entity labels outside fallback chain')) {
+    // If LANGUAGE_NONE is being used as the fallback, when we intended to show
+    // something else, then none of the existing fallback rules have managed to
+    // provide a better alternative. This is our time to act, if translation &
+    // fallback are enabled, and this field is a label replacement field.
+    if ($context['language'] !== LANGUAGE_NONE && variable_get('locale_field_language_fallback', TRUE) && (field_has_translation_handler($entity_type, 'locale') || (function_exists('entity_translation_enabled') && entity_translation_enabled($entity_type)))) {
+      // Figure out what this entity's label field is (if it has one).
+      if (isset($entity_info['entity keys']['label'])) {
+        $label_property = $entity_info['entity keys']['label'];
+        if (isset($entity_info['field replacement'][$label_property]['field']['field_name'])) {
+          $replacement_field = $entity_info['field replacement'][$label_property]['field']['field_name'];
+          // If there is no value for the language being displayed, but there are
+          // values in any language, and no better fallback has already been found,
+          // proceed.
+          $entity = $context['entity'];
+          if (isset($display_language[$replacement_field]) && $display_language[$replacement_field] === LANGUAGE_NONE && !empty($entity->{$replacement_field}) && empty($entity->{$replacement_field}[LANGUAGE_NONE]) && !isset($entity->{$replacement_field}[$context['language']])) {
+            // Run a breadth-first search for all children and then ancestors, so
+            // that the closest 'relatives' are given priority as fallback
+            // candidates. Language hierarchy will have picked up on any matching
+            // ancestors, but this checks children, grandchildren, siblings,
+            // nephews, uncles, cousins, great-uncles, etc (in that order).
+            $already_checked = array();
+            $ancestors = array_keys(language_hierarchy_get_ancestors($context['language']));
+            array_unshift($ancestors, $context['language']);
+            foreach ($ancestors as $ancestor_code) {
+              $tree = language_hierarchy_get_descendants($ancestor_code);
+              if ($tree && !empty($tree->children)) {
+                if ($found = language_hierarchy_breadth_first_search_for_fallback_language($entity->{$replacement_field}, $tree->children, $already_checked)) {
+                  $display_language[$replacement_field] = $found;
+                  return;
+                }
+              }
+            }
+
+            // Finally use the entity's own language as a fallback. Based on
+            // title_entity_language().
+            if (function_exists('entity_translation_enabled') && entity_translation_enabled($entity_type)) {
+              $handler = entity_translation_get_handler($entity_type, $entity, TRUE);
+              $entity_langcode = $handler->getLanguage();
+            }
+            else {
+              $entity_langcode = entity_language($entity_type, $entity);
+            }
+            if ($entity_langcode && isset($entity->{$replacement_field}[$entity_langcode])) {
+              $display_language[$replacement_field] = $entity_langcode;
+              return;
+            }
+
+            // Finally, in the unlikely case that an entity didn't even have its
+            // own language, fall back using the complete original language list.
+            foreach (language_list('weight') as $languages) {
+              foreach ($languages as $language) {
+                if (isset($entity->{$replacement_field}[$language->language])) {
+                  $display_language[$replacement_field] = $language->language;
+                  return;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Helper function to find a value in a descendant language.
+ *
+ * @param array $haystack
+ *   Usually a set of field values taken from an entity, keyed by language code.
+ * @param array $children
+ *   Array of child languages, see language_hierarchy_get_descendants().
+ * @param array $skip
+ *   Array of languages to skip, keyed by language codes.
+ * @return null|string
+ *   A matched language code to use, or NULL.
+ */
+function language_hierarchy_breadth_first_search_for_fallback_language($haystack, $children, &$skip = array()) {
+  $grandchildren = array();
+  foreach (array_diff_key($children, $skip) as $child_code => $child) {
+    $skip[$child_code] = $child_code;
+    if (isset($haystack[$child_code])) {
+      return $child_code;
+    }
+    elseif (!empty($child->children)) {
+      $grandchildren = array_merge($grandchildren, $child->children);
+    }
+  }
+  return $grandchildren ? language_hierarchy_breadth_first_search_for_fallback_language($haystack, $grandchildren, $skip) : NULL;
+}
+
+/**
  * Recursion helper function that populates language_list in hierarchical order
  *
  * @param $langcode
diff --git a/tests/language_hierarchy.test b/tests/language_hierarchy.test
index 39f64b4..b914255 100644
--- a/tests/language_hierarchy.test
+++ b/tests/language_hierarchy.test
@@ -500,3 +500,106 @@ class LanguageHierarchyI18nStringTranslationWebTestCase extends LanguageHierarch
     return $translations;
   }
 }
+
+/**
+ * Functional tests for entity label field replacement with fallbacks.
+ */
+class LanguageHierarchyEntityLabelFieldReplacementWebTestCase extends LanguageHierarchyBaseTestCase {
+
+  // Hierarchical list of languages used in this test.
+  protected $languages = array(
+    // Portuguese, International
+    array('langcode' => 'pt', 'parent' => NULL),
+    // Portuguese, Brazil
+    array('langcode' => 'pt-br', 'parent' => 'pt'),
+    // Portuguese, Portugal
+    array('langcode' => 'pt-pt', 'parent' => 'pt'),
+    // French
+    array('langcode' => 'fr', 'parent' => NULL),
+  );
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Entity label replacement field fallback',
+      'description' => 'Test entity label replacement field language fallback with language inheritance.',
+      'group' => 'Language Hierarchy',
+    );
+  }
+
+  protected $admin_user_permissions = array(
+    'administer languages',
+    'access administration pages',
+    'use entity labels outside fallback chain',
+    'access content',
+    'administer nodes',
+    'administer content types',
+    'administer site configuration',
+  );
+
+  public function setUp() {
+    // We can use any of the modules that define a text group, to use it for testing
+    parent::setUp('language_hierarchy_test');
+  }
+
+  public function testEntityLabel() {
+    $this->loginAdminUser();
+    $this->addLanguages();
+    $this->enableUrlLanguageDetection();
+
+    // Create a node, with values in pt-br.
+    $node_pt_title = $this->randomName();
+    $node_pt_not_title = $this->randomName();
+    $node_pt = (object) array(
+      'uid' => 1,
+      'type' => 'page',
+      'language' => 'pt-br',
+      'title' => $this->randomName(),
+    );
+    node_object_prepare($node_pt);
+    $node_pt->field_title['pt-br'][] = array('value' => $node_pt_title);
+    $node_pt->field_not_title['pt-br'][] = array('value' => $node_pt_not_title);
+
+    node_save($node_pt);
+
+    // We should get the pt-br field value.
+    $this->get('pt-br', 'node/' . $node_pt->nid);
+    $this->assertText($node_pt_title);
+    // We should also see the pt-br not title
+    $this->assertText($node_pt_not_title);
+
+    // We should get the pt-br field value.
+    $this->get('pt', 'node/' . $node_pt->nid);
+    $this->assertText($node_pt_title);
+    // We should also NOT see the pt-br not title
+    $this->assertNoText($node_pt_not_title);
+
+    // We should get the pt-br field value.
+    $this->get('pt-pt', 'node/' . $node_pt->nid);
+    $this->assertText($node_pt_title);
+    // We should also NOT see the pt-br not title
+    $this->assertNoText($node_pt_not_title);
+
+    // We should get the pt-br field value, even in French.
+    $this->get('fr', 'node/' . $node_pt->nid);
+    $this->assertText($node_pt_title);
+    // We should also NOT see the pt-br not title
+    $this->assertNoText($node_pt_not_title);
+
+    // Add a French value, this should get used instead of the pt-br for fr.
+    $node_fr_title = $this->randomName();
+    $node_pt->field_title['fr'][] = array('value' => $node_fr_title);
+    node_save($node_pt);
+
+    // We should get the pt-br field value.
+    $this->get('pt-br', 'node/' . $node_pt->nid);
+    $this->assertText($node_pt_title);
+    // We should also see the pt-br not title
+    $this->assertText($node_pt_not_title);
+
+    // We should get the fr field value.
+    $this->get('fr', 'node/' . $node_pt->nid);
+    $this->assertText($node_fr_title);
+    // We should also NOT see the pt-br not title
+    $this->assertNoText($node_pt_not_title);
+  }
+}
diff --git a/tests/modules/language_hierarchy_test.info b/tests/modules/language_hierarchy_test.info
new file mode 100644
index 0000000..e54153b
--- /dev/null
+++ b/tests/modules/language_hierarchy_test.info
@@ -0,0 +1,8 @@
+name = "Language hierarchy module tests"
+description = "Support module for language hierarchy related testing."
+package = Testing
+core = 7.x
+hidden = TRUE
+
+dependencies[] = language_hierarchy
+dependencies[] = standard
diff --git a/tests/modules/language_hierarchy_test.install b/tests/modules/language_hierarchy_test.install
new file mode 100644
index 0000000..5a23f81
--- /dev/null
+++ b/tests/modules/language_hierarchy_test.install
@@ -0,0 +1,53 @@
+<?php
+
+/**
+ * Implements hook_install().
+ */
+function language_hierarchy_test_install() {
+  // Add a title field to the page node type.
+  $field = array(
+    'field_name' => 'field_title',
+    'type' => 'text',
+    'entity_types' => array('node'),
+    'translatable' => TRUE,
+  );
+  field_create_field($field);
+  $instance = array(
+    'field_name' => 'field_title',
+    'entity_type' => 'node',
+    'bundle' => 'page',
+    'label' => t('Title'),
+    'widget' => array('type' => 'text_textfield'),
+    'settings' => array('display_summary' => TRUE),
+    'display' => array(
+      'default' => array(
+        'label' => 'hidden',
+        'type' => 'text_plain',
+      ),
+    ),
+  );
+  field_create_instance($instance);
+
+  $field = array(
+    'field_name' => 'field_not_title',
+    'type' => 'text',
+    'entity_types' => array('node'),
+    'translatable' => TRUE,
+  );
+  field_create_field($field);
+  $instance = array(
+    'field_name' => 'field_not_title',
+    'entity_type' => 'node',
+    'bundle' => 'page',
+    'label' => t('Not Title'),
+    'widget' => array('type' => 'text_textfield'),
+    'settings' => array('display_summary' => TRUE),
+    'display' => array(
+      'default' => array(
+        'label' => 'hidden',
+        'type' => 'text_plain',
+      ),
+    ),
+  );
+  field_create_instance($instance);
+}
\ No newline at end of file
diff --git a/tests/modules/language_hierarchy_test.module b/tests/modules/language_hierarchy_test.module
new file mode 100644
index 0000000..4192f25
--- /dev/null
+++ b/tests/modules/language_hierarchy_test.module
@@ -0,0 +1,15 @@
+<?php
+
+/**
+ * Implements hook_entity_info_alter().
+ */
+function language_hierarchy_test_entity_info_alter(&$entity_info) {
+  $entity_info['node']['field replacement']['title']['field']['field_name'] = 'field_title';
+}
+
+/**
+ * Implements hook_language_type_info_alter().
+ */
+function language_hierarchy_test_language_types_info_alter(array &$language_types) {
+  unset($language_types[LANGUAGE_TYPE_CONTENT]['fixed']);
+}
\ No newline at end of file
