diff --git a/metatag.module b/metatag.module
index da1d1bf..3bf94cb 100644
--- a/metatag.module
+++ b/metatag.module
@@ -5,12 +5,19 @@
  * Contains metatag.module.
  */
 
+use Drupal\Component\Plugin\Factory\DefaultFactory;
+use Drupal\Core\Database\Query\SelectInterface;
 use Drupal\Core\Entity\ContentEntityInterface;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Url;
+use Drupal\migrate\Plugin\migrate\destination\EntityContentBase;
+use Drupal\migrate\Plugin\migrate\source\SqlBase;
+use Drupal\migrate\Plugin\MigrateSourceInterface;
+use Drupal\migrate\Plugin\MigrationInterface;
+use Drupal\migrate\Row;
 
 /**
  * Implements hook_help().
@@ -308,3 +315,81 @@ function metatag_get_default_tags() {
 
   return $metatags->get('tags');
 }
+
+/**
+ * Implement hook_migrate_prepare_row().
+ *
+ * @param Row $row
+ * @param MigrateSourceInterface $source
+ * @param MigrationInterface $migration
+ */
+function metatag_migrate_prepare_row(Row $row, MigrateSourceInterface $source, MigrationInterface $migration) {
+  // @todo Write a more general version rather than hard-coded.
+  $source_can_have_metatags = in_array($source->getPluginId(), [
+    'd7_node',
+    'd7_node_revision',
+    'taxonomy_term',
+    'd7_user'
+  ]);
+  if ($source_can_have_metatags && $migration->getDestinationPlugin() instanceof EntityContentBase) {
+    $entity_type = NULL;
+    $entity_id = NULL;
+    $revision_id = NULL;
+
+    // @todo Write a more general version rather than switch statement.
+    switch ($source->getPluginId()) {
+      case 'd7_node':
+      case 'd7_node_revision':
+        $entity_type = 'node';
+        $entity_id = $row->getSourceProperty('nid');
+        $revision_id = $row->getSourceProperty('vid');
+        break;
+
+      case 'taxonomy_term':
+        $entity_type = 'taxonomy_term';
+        $entity_id = $row->getSourceProperty('tid');
+        break;
+
+      case 'd7_user':
+        $entity_type = 'user';
+        $entity_id = $row->getSourceProperty('uid');
+        break;
+    }
+
+    /** @var SqlBase $source */
+    /** @var SelectInterface $query */
+    $query = $source->getDatabase()->select('metatag', 'm')
+      ->fields('m', ['data'])
+      ->condition('entity_type', $entity_type)
+      ->condition('entity_id', $entity_id);
+    if (!is_null($revision_id)) {
+      $query->condition('revision_id', $revision_id);
+    }
+    $metatag_value = [];
+    foreach ($query->execute() as $metatag_row) {
+      $metatag_value[]['value'] = $metatag_row->data;
+    }
+    $row->setSourceProperty('field_metatag', $metatag_value);
+  }
+}
+
+/**
+ * Implements hook_migration_plugins_alter().
+ *
+ * @param array $migrations
+ */
+function metatag_migration_plugins_alter(array &$migrations) {
+  foreach ($migrations as &$migration) {
+    if (isset($migration['destination']['plugin'])) {
+      $plugin_definition = \Drupal::service('plugin.manager.migrate.destination')
+        ->getDefinition($migration['destination']['plugin']);
+      $destination_plugin = DefaultFactory::getPluginClass($migration['destination']['plugin'], $plugin_definition);
+      $entity_content_base = 'Drupal\migrate\Plugin\migrate\destination\EntityContentBase';
+
+      if (is_subclass_of($destination_plugin, $entity_content_base) || $destination_plugin == $entity_content_base) {
+        $migration['process']['field_metatag'] = 'field_metatag';
+        $migration['migration_dependencies']['required'][] = 'd7_metatag_field_instance';
+      }
+    }
+  }
+}
diff --git a/migration_templates/d7_metatag_field.yml b/migration_templates/d7_metatag_field.yml
new file mode 100644
index 0000000..0b6f0cd
--- /dev/null
+++ b/migration_templates/d7_metatag_field.yml
@@ -0,0 +1,20 @@
+id: d7_metatag_field
+label: Metatag field
+migration_tags:
+  - Drupal 7
+source:
+  plugin: d7_metatag_field
+  ignore_map: true
+  constants:
+    status: true
+    langcode: und
+    field_name: field_metatag
+    type: metatag
+process:
+  entity_type: entity_type
+  status: 'constants/status'
+  langcode: 'constants/langcode'
+  field_name: 'constants/field_name'
+  type: 'constants/type'
+destination:
+  plugin: entity:field_storage_config
diff --git a/migration_templates/d7_metatag_field_instance.yml b/migration_templates/d7_metatag_field_instance.yml
new file mode 100644
index 0000000..371a60e
--- /dev/null
+++ b/migration_templates/d7_metatag_field_instance.yml
@@ -0,0 +1,22 @@
+id: d7_metatag_field_instance
+label: Metatag field instance
+migration_tags:
+  - Drupal 7
+source:
+  plugin: d7_metatag_field_instance
+  ignore_map: true
+  constants:
+    field_name: field_metatag
+    label: Metatags
+process:
+  entity_type: entity_type
+  field_name: 'constants/field_name'
+  bundle: bundle
+  label: 'constants/label'
+destination:
+  plugin: entity:field_config
+migration_dependencies:
+  required:
+    - d7_metatag_field
+    - d7_node_type
+    - d7_taxonomy_vocabulary
diff --git a/migration_templates/d7_metatag_field_instance_widget_settings.yml b/migration_templates/d7_metatag_field_instance_widget_settings.yml
new file mode 100644
index 0000000..fae4027
--- /dev/null
+++ b/migration_templates/d7_metatag_field_instance_widget_settings.yml
@@ -0,0 +1,20 @@
+id: d7_metatag_field_instance_widget_settings
+label: Metatag field instance widget settings
+migration_tags:
+  - Drupal 7
+source:
+  plugin: d7_metatag_field_instance
+  ignore_map: true
+  constants:
+    form_mode: default
+    field_name: field_metatag
+process:
+  bundle: bundle
+  form_mode: 'constants/form_mode'
+  field_name: 'constants/field_name'
+  entity_type: entity_type
+destination:
+  plugin: component_entity_form_display
+migration_dependencies:
+  required:
+    - d7_metatag_field_instance
diff --git a/src/Plugin/migrate/source/d7/MetatagField.php b/src/Plugin/migrate/source/d7/MetatagField.php
new file mode 100644
index 0000000..48fb524
--- /dev/null
+++ b/src/Plugin/migrate/source/d7/MetatagField.php
@@ -0,0 +1,46 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\metatag\Plugin\migrate\source\d7\MetatagField.
+ */
+
+namespace Drupal\metatag\Plugin\migrate\source\d7;
+
+use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
+
+/**
+ * Drupal 7 metatag field.
+ *
+ * @MigrateSource(
+ *   id = "d7_metatag_field"
+ * )
+ */
+class MetatagField extends DrupalSqlBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function query() {
+    return $this->select('metatag', 'm')
+      ->fields('m', ['entity_type'])
+      ->groupBy('entity_type');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fields() {
+    $fields = array('entity_type' => $this->t('Entity type'));
+    return $fields;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIds() {
+    $ids['entity_type']['type'] = 'string';
+    return $ids;
+  }
+
+}
diff --git a/src/Plugin/migrate/source/d7/MetatagFieldInstance.php b/src/Plugin/migrate/source/d7/MetatagFieldInstance.php
new file mode 100644
index 0000000..b41305a
--- /dev/null
+++ b/src/Plugin/migrate/source/d7/MetatagFieldInstance.php
@@ -0,0 +1,69 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\metatag\Plugin\migrate\source\d7\MetatagFieldInstance.
+ */
+
+namespace Drupal\metatag\Plugin\migrate\source\d7;
+
+use Drupal\Core\Entity\Entity;
+use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
+
+/**
+ * Drupal 7 metatag field instances.
+ *
+ * @MigrateSource(
+ *   id = "d7_metatag_field_instance"
+ * )
+ */
+class MetatagFieldInstance extends DrupalSqlBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function query() {
+    return $this->select('metatag', 'm')
+      ->fields('m', ['entity_type'])
+      ->groupBy('entity_type');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fields() {
+    return array(
+      'entity_type' => $this->t('Entity type'),
+      'bundle' => $this->t('Bundle'),
+    );
+  }
+
+  /**
+   * Returns each entity_type/bundle pair.
+   */
+  public function initializeIterator() {
+    $bundles = [];
+    foreach (parent::initializeIterator() as $instance) {
+      $bundle_info = \Drupal::getContainer()
+        ->get('entity_type.bundle.info')
+        ->getBundleInfo($instance['entity_type']);
+      foreach (array_keys($bundle_info) as $bundle) {
+        $bundles[] = [
+          'entity_type' => $instance['entity_type'],
+          'bundle' => $bundle
+        ];
+      }
+    }
+    return new \ArrayIterator($bundles);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIds() {
+    $ids['entity_type']['type'] = 'string';
+    $ids['bundle']['type'] = 'string';
+    return $ids;
+  }
+
+}
diff --git a/tests/fixtures/drupal7.php b/tests/fixtures/drupal7.php
new file mode 100644
index 0000000..90ec8e9
--- /dev/null
+++ b/tests/fixtures/drupal7.php
@@ -0,0 +1,170 @@
+<?php
+/**
+ * @file
+ * A database agnostic dump for testing purposes.
+ */
+
+use Drupal\Core\Database\Database;
+
+$connection = Database::getConnection();
+
+$connection->schema()->createTable('metatag', array(
+  'fields' => array(
+    'entity_type' => array(
+      'type' => 'varchar',
+      'not null' => TRUE,
+      'length' => '32',
+      'default' => '',
+    ),
+    'entity_id' => array(
+      'type' => 'int',
+      'not null' => TRUE,
+      'size' => 'normal',
+      'default' => '0',
+      'unsigned' => TRUE,
+    ),
+    'revision_id' => array(
+      'type' => 'int',
+      'not null' => TRUE,
+      'size' => 'normal',
+      'default' => '0',
+      'unsigned' => TRUE,
+    ),
+    'language' => array(
+      'type' => 'varchar',
+      'not null' => TRUE,
+      'length' => '32',
+      'default' => '',
+    ),
+    'data' => array(
+      'type' => 'blob',
+      'not null' => TRUE,
+      'size' => 'big',
+    ),
+  ),
+  'primary key' => array(
+    'entity_type',
+    'entity_id',
+    'revision_id',
+    'language',
+  ),
+  'indexes' => array(
+    'type_revision' => array(
+      'entity_type',
+      'revision_id',
+    ),
+  ),
+  'mysql_character_set' => 'utf8',
+));
+
+$connection->insert('metatag')
+->fields(array(
+  'entity_type',
+  'entity_id',
+  'revision_id',
+  'language',
+  'data',
+))
+->values(array(
+  'entity_type' => 'node',
+  'entity_id' => '3',
+  'revision_id' => '3',
+  'language' => 'und',
+  'data' => 'a:1:{s:8:"keywords";a:1:{s:5:"value";s:15:"keynoderevision";}}',
+))
+->values(array(
+  'entity_type' => 'node',
+  'entity_id' => '3',
+  'revision_id' => '4',
+  'language' => 'und',
+  'data' => 'a:1:{s:8:"keywords";a:1:{s:5:"value";s:7:"keynode";}}',
+))
+->values(array(
+  'entity_type' => 'user',
+  'entity_id' => '2',
+  'revision_id' => '0',
+  'language' => 'und',
+  'data' => 'a:1:{s:8:"keywords";a:1:{s:5:"value";s:7:"keyuser";}}',
+))
+->values(array(
+  'entity_type' => 'taxonomy_term',
+  'entity_id' => '2',
+  'revision_id' => '0',
+  'language' => 'und',
+  'data' => 'a:1:{s:8:"keywords";a:1:{s:5:"value";s:12:"keytaxonomy2";}}',
+))
+->execute();
+
+$connection->insert('node')
+->fields(array(
+  'nid',
+  'vid',
+  'type',
+  'language',
+  'title',
+  'uid',
+  'status',
+  'created',
+  'changed',
+  'comment',
+  'promote',
+  'sticky',
+  'tnid',
+  'translate',
+))
+->values(array(
+  'nid' => '3',
+  'vid' => '4',
+  'type' => 'test_content_type',
+  'language' => 'en',
+  'title' => 'An Edited Node',
+  'uid' => '2',
+  'status' => '1',
+  'created' => '1421727515',
+  'changed' => '1441032132',
+  'comment' => '2',
+  'promote' => '1',
+  'sticky' => '0',
+  'tnid' => '0',
+  'translate' => '0',
+))
+->execute();
+
+$connection->insert('node_revision')
+->fields(array(
+  'nid',
+  'vid',
+  'uid',
+  'title',
+  'log',
+  'timestamp',
+  'status',
+  'comment',
+  'promote',
+  'sticky',
+))
+->values(array(
+  'nid' => '3',
+  'vid' => '3',
+  'uid' => '1',
+  'title' => 'A Node',
+  'log' => '',
+  'timestamp' => '1441032131',
+  'status' => '1',
+  'comment' => '2',
+  'promote' => '1',
+  'sticky' => '0',
+))
+->values(array(
+  'nid' => '3',
+  'vid' => '4',
+  'uid' => '1',
+  'title' => 'An Edited Node',
+  'log' => '',
+  'timestamp' => '1441032132',
+  'status' => '1',
+  'comment' => '2',
+  'promote' => '1',
+  'sticky' => '0',
+))
+->execute();
diff --git a/tests/src/Kernel/Migrate/d7/MigrateMetatagTest.php b/tests/src/Kernel/Migrate/d7/MigrateMetatagTest.php
new file mode 100644
index 0000000..bb1e924
--- /dev/null
+++ b/tests/src/Kernel/Migrate/d7/MigrateMetatagTest.php
@@ -0,0 +1,93 @@
+<?php
+
+namespace Drupal\Tests\metatag\Kernel\Migrate\d7;
+
+use Drupal\node\Entity\Node;
+use Drupal\node\NodeInterface;
+use Drupal\taxonomy\Entity\Term;
+use Drupal\taxonomy\TermInterface;
+use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
+use Drupal\user\Entity\User;
+use Drupal\user\UserInterface;
+
+/**
+ * Tests metatag migration.
+ *
+ * @group metatag
+ */
+class MigrateMetatagTest extends MigrateDrupal7TestBase {
+
+  static $modules = [
+    'metatag',
+    'comment',
+    'datetime',
+    'filter',
+    'image',
+    'link',
+    'node',
+    'taxonomy',
+    'telephone',
+    'text',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $this->loadFixture(__DIR__ . '/../../../../../tests/fixtures/drupal7.php');
+
+    $this->installEntitySchema('node');
+    $this->installEntitySchema('comment');
+    $this->installEntitySchema('taxonomy_term');
+    $this->installEntitySchema('file');
+    $this->installConfig(static::$modules);
+    $this->installSchema('node', ['node_access']);
+    $this->installSchema('system', ['sequences']);
+
+    $this->executeMigrations([
+      'd7_metatag_field',
+      'd7_node_type',
+      'd7_taxonomy_vocabulary',
+      'd7_metatag_field_instance',
+      'd7_metatag_field_instance_widget_settings',
+      'd7_user_role',
+      'd7_user',
+      'd7_comment_type',
+      'd7_field',
+      'd7_field_instance',
+      'd7_node:test_content_type',
+      'd7_node:article',
+      'd7_node_revision:test_content_type',
+      'd7_taxonomy_term',
+    ]);
+  }
+
+  /**
+   * Test metatag migration from Drupal 7 to 8.
+   */
+  public function testMetatag() {
+    /** @var Node $node */
+    $node = Node::load(3);
+    $this->assertTrue($node instanceof NodeInterface);
+    $this->assertTrue($node->hasField('field_metatag'));
+    $this->assertSame('a:1:{s:8:"keywords";a:1:{s:5:"value";s:7:"keynode";}}', $node->field_metatag->value);
+
+    $node = node_revision_load(3);
+    $this->assertTrue($node instanceof NodeInterface);
+    $this->assertTrue($node->hasField('field_metatag'));
+    $this->assertSame('a:1:{s:8:"keywords";a:1:{s:5:"value";s:15:"keynoderevision";}}', $node->field_metatag->value);
+
+    /** @var User $user */
+    $user = User::load(2);
+    $this->assertTrue($user instanceof UserInterface);
+    $this->assertTrue($user->hasField('field_metatag'));
+    $this->assertSame('a:1:{s:8:"keywords";a:1:{s:5:"value";s:7:"keyuser";}}', $user->field_metatag->value);
+
+    /** @var Term $term */
+    $term = Term::load(2);
+    $this->assertTrue($term instanceof TermInterface);
+    $this->assertTrue($term->hasField('field_metatag'));
+    $this->assertSame('a:1:{s:8:"keywords";a:1:{s:5:"value";s:12:"keytaxonomy2";}}', $term->field_metatag->value);
+  }
+}
diff --git a/tests/src/Unit/Migrate/d7/MetatagFieldTest.php b/tests/src/Unit/Migrate/d7/MetatagFieldTest.php
new file mode 100644
index 0000000..0cba8e1
--- /dev/null
+++ b/tests/src/Unit/Migrate/d7/MetatagFieldTest.php
@@ -0,0 +1,43 @@
+<?php
+
+namespace Drupal\Tests\metatag\Unit\Migrate\d7;
+
+use Drupal\Tests\migrate\Unit\MigrateSqlSourceTestCase;
+
+/**
+ * Tests D7 metatag field source plugin.
+ *
+ * @group metatag
+ */
+class MetatagFieldTest extends MigrateSqlSourceTestCase {
+
+  const PLUGIN_CLASS = 'Drupal\metatag\Plugin\migrate\source\d7\MetatagField';
+
+  protected $migrationConfiguration = array(
+    'id' => 'test',
+    'source' => array(
+      'plugin' => 'd7_metatag_field',
+    ),
+  );
+
+  protected $expectedResults = array(
+    array(
+      'entity_type' => 'node',
+    ),
+    array(
+      'entity_type' => 'taxonomy_term',
+    ),
+    array(
+      'entity_type' => 'user',
+    ),
+  );
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    $this->databaseContents['metatag'] = $this->expectedResults;
+    parent::setUp();
+  }
+
+}
