diff --git a/metatag.install b/metatag.install
index 51aebae..bfab1db 100644
--- a/metatag.install
+++ b/metatag.install
@@ -244,11 +244,176 @@ function metatag_update_7003() {
 }
 
 /**
- * Update all records in the metatag table and assign each the correct language
- * value, will also resolve problems created during the release of beta3. This
- * might take a while, depending on how much data needs to be converted.
+ * Replaced by updates 7009, 7010, 7011, 7012 and 7013.
  */
-function metatag_update_7004(&$sandbox) {
+function metatag_update_7004() {
+  // Do nothing.
+}
+
+/**
+ * Removing wrong metatag watchdog entries that break the admin/reports/dblog
+ * page.
+ */
+function metatag_update_7005() {
+  db_delete('watchdog')
+    ->condition('type', 'metatag')
+    ->condition('variables', serialize('info'))
+    ->execute();
+}
+
+/**
+ * Remove metatag records that were added by old versions of the module for
+ * entities that don't actually support meta tags. A more complete version of
+ * this will be added later on after it's (hopefully) guaranteed that all
+ * modules have updated to the correct API usage.
+ */
+function metatag_update_7006() {
+  $types = array(
+    // Core.
+    'comment',
+    'menu_link',
+    'taxonomy_vocabulary',
+    // Some contrib entities.
+    'mailchimp_list',
+    'profile2',
+    'profile2_type',
+    'redirect',
+    'rules_config',
+    'wysiwyg_profile',
+  );
+  foreach ($types as $type) {
+    $num_deleted = db_delete('metatag')
+      ->condition('entity_type', $type)
+      ->execute();
+    if ($num_deleted > 0) {
+      drupal_set_message(t('Removed @count meta tag record(s) for the @type entity type, it does not support meta tags.', array('@count' => $num_deleted, '@type' => $type)));
+    }
+  }
+}
+
+/**
+ * Remove metatag records for objects that have been deleted; older versions of
+ * Metatag may have failed to purge these.
+ */
+function metatag_update_7007() {
+  $result = db_query("DELETE m
+    FROM {metatag} m
+    LEFT OUTER JOIN {node} n
+    	ON m.entity_id=n.nid
+    WHERE m.entity_type='node'
+    	AND n.nid IS NULL");
+  if ($result->rowCount() > 0) {
+    drupal_set_message(t('Removed @count meta tag record(s) for nodes that had been purged.', array('@count' => $result->rowCount())));
+  }
+
+  $result = db_query("DELETE m
+    FROM {metatag} m
+    LEFT OUTER JOIN {users} u
+    	ON m.entity_id=u.uid
+    WHERE m.entity_type='user'
+    	AND u.uid IS NULL");
+  if ($result->rowCount() > 0) {
+    drupal_set_message(t('Removed @count meta tag record(s) for users that had been purged.', array('@count' => $result->rowCount())));
+  }
+
+  $result = db_query("DELETE m
+    FROM {metatag} m
+    LEFT OUTER JOIN {taxonomy_term_data} t
+    	ON m.entity_id=t.tid
+    WHERE m.entity_type='taxonomy_term'
+    	AND t.tid IS NULL");
+  if ($result->rowCount() > 0) {
+    drupal_set_message(t('Removed @count meta tag record(s) for taxonomy terms that had been purged.', array('@count' => $result->rowCount())));
+  }
+}
+
+/**
+ * Remove metatag any empty records that may be hanging around from old
+ * releases.
+ */
+function metatag_update_7008() {
+  $result = db_query("DELETE m FROM {metatag} m WHERE m.data IS NULL or m.data = '' OR m.data = :empty", array(':empty' => serialize(array())));
+  if ($result->rowCount() > 0) {
+    drupal_set_message(t('Purged @count empty meta tag record(s).', array('@count' => $result->rowCount())));
+  }
+}
+
+/**
+ * Fix metatags for taxonomy terms.
+ */
+function metatag_update_7009() {
+  // Remove duplicates.
+  _metatag_remove_dupes('taxonomy_term');
+
+  // Taxonomy entities don't support a 'language' option, so reset them to
+  // LANGUAGE_NONE.
+  $result = db_query("UPDATE {metatag} SET language = :language WHERE entity_type='taxonomy_term'", array(':language' => LANGUAGE_NONE));
+  if ($result->rowCount() > 0) {
+    drupal_set_message(t('Fixed language values for @count taxonomy terms.', array('@count' => $result->rowCount())));
+  }
+}
+
+/**
+ * Fix metatags for users.
+ */
+function metatag_update_7010() {
+  // Remove duplicates.
+  _metatag_remove_dupes('user');
+
+  // Update User values.
+  $result = db_query("UPDATE {metatag} AS m INNER JOIN {users} u ON m.entity_id=u.uid SET m.language = u.language WHERE m.entity_type='user' AND u.language!=''");
+  if ($result->rowCount() > 0) {
+    drupal_set_message(t('Fixed language values for @count users that had a language setting.', array('@count' => $result->rowCount())));
+  }
+  $result = db_query("UPDATE {metatag} AS m INNER JOIN {users} u ON m.entity_id=u.uid SET m.language = :language WHERE m.entity_type='user' AND u.language=''", array(':language' => LANGUAGE_NONE));
+  if ($result->rowCount() > 0) {
+    drupal_set_message(t('Fixed language values for @count users that didn\'t have a language setting.', array('@count' => $result->rowCount())));
+  }
+}
+
+/**
+ * Fix metatags for nodes.
+ */
+function metatag_update_7011() {
+  // Remove duplicates.
+  _metatag_remove_dupes('node');
+
+  // Update Node values.
+  $result = db_query("UPDATE {metatag} AS m INNER JOIN {node} n ON m.entity_id=n.nid AND m.entity_type='node' SET m.language = n.language");
+  if ($result->rowCount() > 0) {
+    drupal_set_message(t('Fixed language values for @count nodes.', array('@count' => $result->rowCount())));
+  }
+}
+
+/**
+ * Remove duplicate {metatag} records for non-core entities.
+ */
+function metatag_update_7012() {
+  $records = db_select('metatag', 'm')
+    ->fields('m', array('entity_type'))
+    ->condition('m.entity_type', array('node', 'taxonomy_term', 'user'), 'NOT IN')
+    ->orderBy('m.entity_type', 'ASC')
+    ->orderBy('m.entity_id', 'ASC')
+    ->distinct()
+    ->execute();
+
+  $entity_types = array();
+  foreach ($records as $record) {
+    $entity_types[] = $record->entity_type;
+    // Remove duplicates.
+    _metatag_remove_dupes($record->entity_type);
+  }
+
+  if (empty($entity_types)) {
+    drupal_set_message(t('There were no other records to fix.'));
+  }
+}
+
+/**
+ * Fix the metatag language value for all non-core entity records. This might
+ * take a while, depending on how much data needs to be converted.
+ */
+function metatag_update_7013(&$sandbox) {
   // Use the sandbox at your convenience to store the information needed
   // to track progression between successive calls to the function.
   if (!isset($sandbox['progress'])) {
@@ -259,9 +424,10 @@ function metatag_update_7004(&$sandbox) {
     // way to do this, so we're going to cache all record keys and manually
     // step through them.
     $records = db_select('metatag', 'm')
-      ->fields('m', array('entity_type', 'entity_id', 'language'))
-      ->orderBy('entity_type', 'ASC')
-      ->orderBy('entity_id', 'ASC')
+      ->fields('m', array('entity_type', 'entity_id'))
+      ->condition('m.entity_type', array('node', 'taxonomy_term', 'user'), 'NOT IN')
+      ->orderBy('m.entity_type', 'ASC')
+      ->orderBy('m.entity_id', 'ASC')
       ->execute();
     $sandbox['records'] = array();
     foreach ($records as $record) {
@@ -273,8 +439,11 @@ function metatag_update_7004(&$sandbox) {
     // A place to store messages during the run.
     $sandbox['messages'] = array();
 
-    // An initial record of the number of records to be upgraded.
-    watchdog('metatag', 'Update 7004: !count records to upgrade.', array('!count' => $sandbox['max']), WATCHDOG_INFO);
+    // An initial record of the number of records to be updated.
+    watchdog('metatag', 'Update 7013: !count records to update.', array('!count' => $sandbox['max']), WATCHDOG_INFO);
+    if (drupal_is_cli()) {
+      drupal_set_message(t('Update 7013: !count records to update.', array('!count' => $sandbox['max'])));
+    }
 
     // Last record processed.
     $sandbox['current_record'] = -1;
@@ -282,16 +451,19 @@ function metatag_update_7004(&$sandbox) {
 
   // If there's no data, don't bother with the extra work.
   if (empty($sandbox['max'])) {
-    return t('No records needed to be updated.');
+    if (drupal_is_cli()) {
+      drupal_set_message(t('Update 7013: No records need updating.'));
+    }
+    return t('No records need updating.');
   }
 
   // Proceed as normal.
   else {
-    // Process records by groups of 50 (arbitrary value).
+    // Process records by groups of 10 (arbitrary value).
     // When a group is processed, the batch update engine determines
     // whether it should continue processing in the same request or provide
     // progress feedback to the user and wait for the next request.
-    $limit = 50;
+    $limit = 10;
 
     // The for loop will run as normal when ran via update.php, but when ran
     // via Drush it'll just run 'til it's finished.
@@ -301,7 +473,7 @@ function metatag_update_7004(&$sandbox) {
     }
 
     // Set default values.
-    for ($x = 0; $x < $limit; $x += $increment) {
+    for ($ctr = 0; $ctr < $limit; $ctr += $increment) {
       $sandbox['current_record']++;
       if (empty($sandbox['records'][$sandbox['current_record']])) {
         break;
@@ -310,7 +482,7 @@ function metatag_update_7004(&$sandbox) {
       // Shortcuts for later.
       $entity_type = $sandbox['records'][$sandbox['current_record']]->entity_type;
       $entity_id = $sandbox['records'][$sandbox['current_record']]->entity_id;
-      $language = $sandbox['records'][$sandbox['current_record']]->language;
+      $language = '';
 
       // Load the entity.
       $entities = entity_load($entity_type, array($entity_id));
@@ -320,53 +492,23 @@ function metatag_update_7004(&$sandbox) {
         // Make sure that the entity has a language set and that it isn't the
         // same as the meta tag record's language.
         if (!empty($entity)) {
-          // If the record has multiple values already, i.e. someone saved a
-          // new record because they thought the records were missing.
-          try {
-            // If there's a (non-empty) language value, use it.
-            if (!empty($entity->language)) {
-              // The language values are different.
-              if ($entity->language != $language) {
-                // Update the record with the entity's language value.
-                db_update('metatag')
-                  ->fields(array('language' => $entity->language))
-                  ->condition('entity_type', $entity_type)
-                  ->condition('entity_id', $entity_id)
-                  ->condition('language', $language)
-                  ->execute();
-              }
-              // The language values are the same.
-              else {
-                // Do nothing.
-              }
-            }
-            // There's no language value.
-            else {
-              // Assign the global 'no language' value.
-              db_update('metatag')
-                ->fields(array('language' => LANGUAGE_NONE))
-                ->condition('entity_type', $entity_type)
-                ->condition('entity_id', $entity_id)
-                ->condition('language', $language)
-                ->execute();
-            }
+          // If there's a (non-empty) language value, use it.
+          if (function_exists('entity_language')) {
+            $new_language = entity_language($entity_type, $entity);
           }
-          catch (Exception $e) {
-            // Delete the newer record.
-            db_delete('metatag')
-              ->condition('language', $entity->language)
-              ->condition('entity_type', $entity_type)
-              ->condition('entity_id', $entity_id)
-              ->execute();
-            // Update the old one again.
-            db_update('metatag')
-              ->fields(array('language' => $entity->language))
-              ->condition('entity_type', $entity_type)
-              ->condition('entity_id', $entity_id)
-              ->condition('language', $language)
-              ->execute();
-            $sandbox['messages'][] = t('The duplicate record for :type record #:id has been removed, leaving the older record in place.', array(':type' => $entity_type, ':id' => $entity_id));
+          elseif (!empty($entity->language)) {
+            $new_language = $entity->language;
           }
+          if (empty($new_language)) {
+            $new_language = LANGUAGE_NONE;
+          }
+          // Update the 'language' value.
+          db_update('metatag')
+            ->fields(array('language' => $new_language))
+            ->condition('entity_type', $entity_type)
+            ->condition('entity_id', $entity_id)
+            ->condition('language', $language)
+            ->execute();
         }
       }
 
@@ -376,7 +518,7 @@ function metatag_update_7004(&$sandbox) {
 
     // A per-iterationl message, only record if not running via Drush.
     if (!drupal_is_cli()) {
-      watchdog('metatag', 'Update 7004: !count records were updated.', array('!count' => $x), WATCHDOG_INFO);
+      watchdog('metatag', 'Update 7013: !count records were updated.', array('!count' => $ctr), WATCHDOG_INFO);
     }
 
     // Set the "finished" status, to tell batch engine whether this function
@@ -389,7 +531,10 @@ function metatag_update_7004(&$sandbox) {
       cache_clear_all('*', 'cache_metatag', TRUE);
 
       // A final log of the number of records that were converted.
-      watchdog('metatag', 'Update 7004: !count records were updated in total.', array('!count' => $sandbox['progress']), WATCHDOG_INFO);
+      watchdog('metatag', 'Update 7013: !count records were updated in total.', array('!count' => $sandbox['progress']), WATCHDOG_INFO);
+      if (drupal_is_cli()) {
+        drupal_set_message(t('Update 7013: !count records were updated.', array('!count' => $sandbox['progress'])));
+      }
 
       // hook_update_N() may optionally return a string which will be displayed
       // to the user.
@@ -399,89 +544,138 @@ function metatag_update_7004(&$sandbox) {
 }
 
 /**
- * Removing wrong metatag watchdog entries that break the admin/reports/dblog
- * page.
+ * Remove duplicate records for a given content type.
+ *
+ * @param $entity_type
+ *   The name of an entity type to check for.
  */
-function metatag_update_7005() {
-  db_delete('watchdog')
-    ->condition('type', 'metatag')
-    ->condition('variables', serialize('info'))
-    ->execute();
-}
+function _metatag_remove_dupes($entity_type) {
+  $purge_count = 0;
+
+  // First step: fix the records. There should not be multiple records for the
+  // same entity_id with different languages.
+  $dupe_records = db_query("SELECT m.entity_id, count(m.language) AS the_count
+    FROM metatag m
+    WHERE
+      m.entity_type = :type
+    GROUP BY m.entity_id
+    HAVING the_count > 1", array(':type' => $entity_type));
+
+  if (!empty($dupe_records)) {
+    foreach ($dupe_records as $record) {
+      $entity_id = $record->entity_id;
+      $langs = db_query("SELECT m.entity_id, m.language, m.data FROM metatag m WHERE m.entity_type = :type AND m.entity_id = :id", array(':type' => $entity_type, ':id' => $entity_id))->fetchAll();
+
+      // Work out which language record to remove. Will need to store this as
+      // an array incase there are multiple records to purge.
+      $langs_to_remove = array();
+
+      // Check for duplicate records.
+      // Outer loop starts from the beginning.
+      for ($outer = 0; $outer < count($langs); $outer++) {
+        // This record may have been removed already.
+        if (isset($langs[$outer])) {
+          // Inner loop starts from the end.
+          for ($inner = count($langs) - 1; $inner > 0; $inner--) {
+            // Work out if the outer loop's data is the same as the inner
+            // loop's.
+            if (isset($langs[$inner]) && $langs[$outer]->data == $langs[$inner]->data) {
+              // Remove the second record.
+              $langs_to_remove[] = $langs[$inner]->language;
+              unset($langs[$inner]);
+            }
+          }
+        }
+      }
 
-/**
- * Remove metatag records that were added by old versions of the module for
- * entities that don't actually support meta tags. A more complete version of
- * this will be added later on after it's (hopefully) guaranteed that all
- * modules have updated to the correct API usage.
- */
-function metatag_update_7006() {
-  $types = array(
-    // Core.
-    'comment',
-    'menu_link',
-    'taxonomy_vocabulary',
-    // Some contrib entities.
-    'mailchimp_list',
-    'profile2',
-    'profile2_type',
-    'redirect',
-    'rules_config',
-    'wysiwyg_profile',
-  );
-  foreach ($types as $type) {
-    $num_deleted = db_delete('metatag')
-      ->condition('entity_type', $type)
-      ->execute();
-    if ($num_deleted > 0) {
-      drupal_set_message(t('Removed @count meta tag record(s) for the @type entity type, it does not support meta tags.', array('@count' => $num_deleted, '@type' => $type)));
-    }
-  }
-}
+      // Only one record left.
+      if (count($langs) == 1) {
+        // This is how it should be, this record is fine.
+      }
+      // Two records, limited possibilities.
+      elseif (count($langs) == 2) {
+        // Work out the entity's language.
+        $entity = entity_load($entity_type, $entity_id);
+        $entity_language = NULL;
+        if (function_exists('entity_language')) {
+          $entity_language = entity_language($entity_type, $entity);
+        }
+        elseif (isset($entity->language)) {
+          $entity_language = $entity->language;
+        }
+        if (empty($language)) {
+          $entity_language = LANGUAGE_NONE;
+        }
 
-/**
- * Remove metatag records for objects that have been deleted; older versions of
- * Metatag may have failed to purge these.
- */
-function metatag_update_7007() {
-  $result = db_query("DELETE m
-    FROM {metatag} m
-    LEFT OUTER JOIN {node} n
-    	ON m.entity_id=n.nid
-    WHERE m.entity_type='node'
-    	AND n.nid IS NULL");
-  if ($result->rowCount() > 0) {
-    drupal_set_message(t('Removed @count meta tag record(s) for nodes that had been purged.', array('@count' => $result->rowCount())));
-  }
+        // Work out if the entity's language record exists.
+        $lang_pos = NULL;
+        foreach ($langs as $key => $record) {
+          if ($record->language == $entity_language) {
+            $lang_pos = $key;
+            break;
+          }
+        }
+        // If the language record exists, delete the others.
+        if (isset($lang_pos)) {
+          foreach ($langs as $key => $record) {
+            if ($record->language != $entity_language) {
+              $langs_to_remove[] = $record->language;
+            }
+          }
+        }
+        // Otherwise look for a record for the site's default language.
+        else {
+          foreach ($langs as $key => $record) {
+            if ($record->language == $GLOBALS['language']->language) {
+              $lang_pos = $key;
+              break;
+            }
+          }
+          if (isset($lang_pos)) {
+            foreach ($langs as $key => $record) {
+              if ($record->language != $GLOBALS['language']->language) {
+                $langs_to_remove[] = $record->language;
+              }
+            }
+          }
+          // Finally check for LANGUAGE_NONE.
+          else {
+            foreach ($langs as $key => $record) {
+              if ($record->language == LANGUAGE_NONE) {
+                $lang_pos = $key;
+                break;
+              }
+            }
+            if (isset($lang_pos)) {
+              foreach ($langs as $key => $record) {
+                if ($record->language != LANGUAGE_NONE) {
+                  $langs_to_remove[] = $record->language;
+                }
+              }
+            }
+          }
+        }
+      }
 
-  $result = db_query("DELETE m
-    FROM {metatag} m
-    LEFT OUTER JOIN {users} u
-    	ON m.entity_id=u.uid
-    WHERE m.entity_type='user'
-    	AND u.uid IS NULL");
-  if ($result->rowCount() > 0) {
-    drupal_set_message(t('Removed @count meta tag record(s) for users that had been purged.', array('@count' => $result->rowCount())));
-  }
+      // Purge the redundant records.
+      if (!empty($langs_to_remove)) {
+        $purge_count += db_delete('metatag')
+          ->condition('entity_type', $entity_type)
+          ->condition('entity_id', $entity_id)
+          ->condition('language', $langs_to_remove)
+          ->execute();
+      }
+    }
 
-  $result = db_query("DELETE m
-    FROM {metatag} m
-    LEFT OUTER JOIN {taxonomy_term_data} t
-    	ON m.entity_id=t.tid
-    WHERE m.entity_type='taxonomy_term'
-    	AND t.tid IS NULL");
-  if ($result->rowCount() > 0) {
-    drupal_set_message(t('Removed @count meta tag record(s) for taxonomy terms that had been purged.', array('@count' => $result->rowCount())));
+    if (!empty($purge_count)) {
+      drupal_set_message(t('Purged :count duplicate :entity_type record(s).', array(':count' => $purge_count, ':entity_type' => $entity_type)));
+      watchdog('metatag', 'Purged :count duplicate :entity_type record(s).', array(':count' => $purge_count, ':entity_type' => $entity_type));
+      return;
+    }
   }
-}
 
-/**
- * Remove metatag any empty records that may be hanging around from old
- * releases.
- */
-function metatag_update_7008() {
-  $result = db_query("DELETE m FROM {metatag} m WHERE m.data IS NULL or m.data = '' OR m.data = :empty", array(':empty' => serialize(array())));
-  if ($result->rowCount() > 0) {
-    drupal_set_message(t('Purged @count empty meta tag record(s).', array('@count' => $result->rowCount())));
+  if (empty($purge_count)) {
+    drupal_set_message(t('No duplicate :entity_type records were found (this is a good thing).', array(':entity_type' => $entity_type)));
+    watchdog('metatag', 'No duplicate :entity_type records were found (this is a good thing).', array(':entity_type' => $entity_type));
   }
 }
