diff --git a/core/modules/migrate/tests/src/Unit/MigrateSqlSourceTestCase.php b/core/modules/migrate/tests/src/Unit/MigrateSqlSourceTestCase.php
index 98180d5..57630cb 100644
--- a/core/modules/migrate/tests/src/Unit/MigrateSqlSourceTestCase.php
+++ b/core/modules/migrate/tests/src/Unit/MigrateSqlSourceTestCase.php
@@ -69,33 +69,36 @@
    * {@inheritdoc}
    */
   protected function setUp() {
-    $module_handler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
-    $entity_manager = $this->getMock('Drupal\Core\Entity\EntityManagerInterface');
-
     $migration = $this->getMigration();
-    $migration->expects($this->any())
-      ->method('getHighWater')
-      ->will($this->returnValue(static::ORIGINAL_HIGH_WATER));
-
-    // Setup the plugin.
-    $plugin_class = static::PLUGIN_CLASS;
-    $plugin = new $plugin_class($this->migrationConfiguration['source'], $this->migrationConfiguration['source']['plugin'], array(), $migration, $entity_manager);
-
-    // Do some reflection to set the database and moduleHandler.
-    $plugin_reflection = new \ReflectionClass($plugin);
-    $database_property = $plugin_reflection->getProperty('database');
+    $migration->method('getHighWater')
+      ->willReturn(static::ORIGINAL_HIGH_WATER);
+
+    // Create the source plugin, allowing the test to provide additional
+    // constructor arguments via getPluginDependencies().
+    $reflector = new \ReflectionClass(static::PLUGIN_CLASS);
+    $arguments = [
+      $this->migrationConfiguration['source'],
+      $this->migrationConfiguration['source']['plugin'],
+      [],
+      $migration,
+    ];
+    $arguments = array_merge($arguments, $this->getPluginDependencies());
+    $plugin = $reflector->newInstanceArgs($arguments);
+
+    // Set the database and the module handler onto our plugin using reflection,
+    // since the relevant properties aren't normally accessible.
+    $database_property = $reflector->getProperty('database');
     $database_property->setAccessible(TRUE);
-    $module_handler_property = $plugin_reflection->getProperty('moduleHandler');
-    $module_handler_property->setAccessible(TRUE);
-
-    // Set the database and the module handler onto our plugin.
     $database_property->setValue($plugin, $this->getDatabase($this->databaseContents + array('test_map' => array())));
+
+    $module_handler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
+    $module_handler_property = $reflector->getProperty('moduleHandler');
+    $module_handler_property->setAccessible(TRUE);
     $module_handler_property->setValue($plugin, $module_handler);
 
     $plugin->setStringTranslation($this->getStringTranslationStub());
-    $migration->expects($this->any())
-      ->method('getSourcePlugin')
-      ->will($this->returnValue($plugin));
+    $migration->method('getSourcePlugin')
+      ->willReturn($plugin);
     $this->source = $plugin;
   }
 
@@ -115,4 +118,15 @@ protected function getValue($row, $key) {
     return $row->getSourceProperty($key);
   }
 
+  /**
+   * Mocks dependencies needed by the plugin's constructor.
+   *
+   * @return array
+   */
+  protected function getPluginDependencies() {
+    return [
+      $this->getMock('\Drupal\Core\Entity\EntityManagerInterface'),
+    ];
+  }
+
 }
diff --git a/core/modules/migrate_drupal/src/Plugin/migrate/source/d6/Field.php b/core/modules/migrate_drupal/src/Plugin/migrate/source/d6/Field.php
index 3738dce..bfeeca1 100644
--- a/core/modules/migrate_drupal/src/Plugin/migrate/source/d6/Field.php
+++ b/core/modules/migrate_drupal/src/Plugin/migrate/source/d6/Field.php
@@ -24,25 +24,10 @@ class Field extends DrupalSqlBase {
    * {@inheritdoc}
    */
   public function query() {
-    $query = $this->select('content_node_field', 'cnf')
-      ->fields('cnf', array(
-        'field_name',
-        'type',
-        'global_settings',
-        'required',
-        'multiple',
-        'db_storage',
-        'module',
-        'db_columns',
-        'active',
-        'locked',
-      ))
-      ->fields('cnfi', array(
-        'widget_type',
-        'widget_settings',
-      ));
-    $query->join('content_node_field_instance', 'cnfi', 'cnfi.field_name = cnf.field_name');
-    $query->orderBy('field_name');
+    $query = $this->select('content_node_field_instance', 'cnfi');
+    $query->fields('cnfi');
+    $query->join('content_node_field', 'cnf', 'cnf.field_name = cnfi.field_name');
+    $query->fields('cnf');
 
     return $query;
   }
@@ -52,6 +37,7 @@ public function query() {
    */
   public function fields() {
     return array(
+      // content_node_field
       'field_name' => $this->t('Field name'),
       'type' => $this->t('Type (text, integer, ....)'),
       'global_settings' => $this->t('Global settings. Shared with every field instance.'),
@@ -62,6 +48,16 @@ public function fields() {
       'db_columns' => $this->t('DB Columns'),
       'active' => $this->t('Active'),
       'locked' => $this->t('Locked'),
+      // content_node_field_instance
+      'type_name' => $this->t('The node type to which the field is attached.'),
+      'weight' => $this->t('Weight'),
+      'label' => $this->t('Label'),
+      'widget_type' => $this->t('Widget type'),
+      'widget_settings' => $this->t('Widget settings'),
+      'display_settings' => $this->t('Display settings'),
+      'description' => $this->t('Description'),
+      'widget_module' => $this->t('Widget module'),
+      'widget_active' => $this->t('Whether the widget is active'),
     );
   }
 
@@ -69,13 +65,15 @@ public function fields() {
    * {@inheritdoc}
    */
   public function prepareRow(Row $row) {
-    // Unserialize data.
-    $global_settings = unserialize($row->getSourceProperty('global_settings'));
-    $widget_settings = unserialize($row->getSourceProperty('widget_settings'));
-    $db_columns = unserialize($row->getSourceProperty('db_columns'));
-    $row->setSourceProperty('global_settings', $global_settings);
-    $row->setSourceProperty('widget_settings', $widget_settings);
-    $row->setSourceProperty('db_columns', $db_columns);
+    $serialized_properties = [
+      'widget_settings',
+      'display_settings',
+      'global_settings',
+      'db_columns',
+    ];
+    foreach ($serialized_properties as $property) {
+      $row->setSourceProperty($property, unserialize($row->getSourceProperty($property)));
+    }
     return parent::prepareRow($row);
   }
 
diff --git a/core/modules/migrate_drupal/src/Plugin/migrate/source/d6/FieldInstance.php b/core/modules/migrate_drupal/src/Plugin/migrate/source/d6/FieldInstance.php
index 5b42504..712c22a 100644
--- a/core/modules/migrate_drupal/src/Plugin/migrate/source/d6/FieldInstance.php
+++ b/core/modules/migrate_drupal/src/Plugin/migrate/source/d6/FieldInstance.php
@@ -7,9 +7,6 @@
 
 namespace Drupal\migrate_drupal\Plugin\migrate\source\d6;
 
-use Drupal\migrate\Row;
-use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
-
 /**
  * Drupal 6 field instances source from database.
  *
@@ -18,76 +15,13 @@
  *   source_provider = "content"
  * )
  */
-class FieldInstance extends DrupalSqlBase {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function query() {
-    $query = $this->select('content_node_field_instance', 'cnfi')
-      ->fields('cnfi', array(
-        'field_name',
-        'type_name',
-        'weight',
-        'label',
-        'widget_type',
-        'widget_settings',
-        'display_settings',
-        'description',
-        'widget_module',
-        'widget_active',
-        'description',
-      ))
-      ->fields('cnf', array(
-        'required',
-        'active',
-        'global_settings',
-      ));
-
-    $query->join('content_node_field', 'cnf', 'cnf.field_name = cnfi.field_name');
-    $query->orderBy('weight');
-
-    return $query;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function fields() {
-    return array(
-      'field_name' => $this->t('The machine name of field.'),
-      'type_name' => $this->t('Content type where is used this field.'),
-      'weight' => $this->t('Weight.'),
-      'label' => $this->t('A name to show.'),
-      'widget_type' => $this->t('Widget type.'),
-      'widget_settings' => $this->t('Serialize data with widget settings.'),
-      'display_settings' => $this->t('Serialize data with display settings.'),
-      'description' => $this->t('A description of field.'),
-      'widget_module' => $this->t('Module that implements widget.'),
-      'widget_active' => $this->t('Status of widget'),
-      'module' => $this->t('The module that provides the field.'),
-    );
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function prepareRow(Row $row) {
-    // Unserialize data.
-    $widget_settings = unserialize($row->getSourceProperty('widget_settings'));
-    $display_settings = unserialize($row->getSourceProperty('display_settings'));
-    $global_settings = unserialize($row->getSourceProperty('global_settings'));
-    $row->setSourceProperty('widget_settings', $widget_settings);
-    $row->setSourceProperty('display_settings', $display_settings);
-    $row->setSourceProperty('global_settings', $global_settings);
-    return parent::prepareRow($row);
-  }
+class FieldInstance extends Field {
 
   /**
    * {@inheritdoc}
    */
   public function getIds() {
-    $ids = array(
+    return array(
       'field_name' => array(
         'type' => 'string',
         'alias' => 'cnfi',
@@ -96,7 +30,6 @@ public function getIds() {
         'type' => 'string',
       ),
     );
-    return $ids;
   }
 
 }
diff --git a/core/modules/migrate_drupal/src/Plugin/migrate/source/d6/FieldInstancePerFormDisplay.php b/core/modules/migrate_drupal/src/Plugin/migrate/source/d6/FieldInstancePerFormDisplay.php
index 5bbb04d..3051678 100644
--- a/core/modules/migrate_drupal/src/Plugin/migrate/source/d6/FieldInstancePerFormDisplay.php
+++ b/core/modules/migrate_drupal/src/Plugin/migrate/source/d6/FieldInstancePerFormDisplay.php
@@ -7,8 +7,6 @@
 
 namespace Drupal\migrate_drupal\Plugin\migrate\source\d6;
 
-use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
-
 /**
  * The field instance per form display source class.
  *
@@ -16,7 +14,7 @@
  *   id = "d6_field_instance_per_form_display"
  * )
  */
-class FieldInstancePerFormDisplay extends DrupalSqlBase {
+class FieldInstancePerFormDisplay extends FieldInstance {
 
   /**
    * {@inheritdoc}
@@ -44,58 +42,4 @@ protected function initializeIterator() {
     return new \ArrayIterator($rows);
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function query() {
-    $query = $this->select('content_node_field_instance', 'cnfi')
-      ->fields('cnfi', array(
-        'field_name',
-        'type_name',
-        'weight',
-        'label',
-        'widget_type',
-        'widget_settings',
-        'display_settings',
-        'description',
-        'widget_module',
-        'widget_active',
-      ))
-      ->fields('cnf', array(
-        'type',
-        'module',
-      ));
-    $query->join('content_node_field', 'cnf', 'cnfi.field_name = cnf.field_name');
-    $query->orderBy('weight');
-
-    return $query;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function fields() {
-    return array(
-      'field_name' => $this->t('The machine name of field.'),
-      'type_name' => $this->t('Content type where this field is used.'),
-      'weight' => $this->t('Weight.'),
-      'label' => $this->t('A name to show.'),
-      'widget_type' => $this->t('Widget type.'),
-      'widget_settings' => $this->t('Serialize data with widget settings.'),
-      'display_settings' => $this->t('Serialize data with display settings.'),
-      'description' => $this->t('A description of field.'),
-      'widget_module' => $this->t('Module that implements widget.'),
-      'widget_active' => $this->t('Status of widget'),
-    );
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getIds() {
-    $ids['type_name']['type'] = 'string';
-    $ids['field_name']['type'] = 'string';
-    return $ids;
-  }
-
 }
diff --git a/core/modules/migrate_drupal/src/Plugin/migrate/source/d6/Node.php b/core/modules/migrate_drupal/src/Plugin/migrate/source/d6/Node.php
index d7579fd..e30742b 100644
--- a/core/modules/migrate_drupal/src/Plugin/migrate/source/d6/Node.php
+++ b/core/modules/migrate_drupal/src/Plugin/migrate/source/d6/Node.php
@@ -7,9 +7,13 @@
 
 namespace Drupal\migrate_drupal\Plugin\migrate\source\d6;
 
+use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\migrate\Entity\MigrationInterface;
+use Drupal\migrate\Plugin\MigratePluginManager;
 use Drupal\migrate\Row;
 use Drupal\migrate\Plugin\SourceEntityInterface;
 use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Drupal 6 node source from database.
@@ -33,6 +37,56 @@ class Node extends DrupalSqlBase implements SourceEntityInterface {
   protected $filterDefaultFormat;
 
   /**
+   * Information on which tables exist.
+   *
+   * @var array
+   */
+  protected $tables = [];
+
+  /**
+   * TRUE when CCK is enabled and the schema is correct.
+   *
+   * @var bool
+   */
+  protected $cckSchemaCorrect;
+
+  /**
+   * The d6_field source plugin.
+   *
+   * @var \Drupal\migrate\Plugin\MigrateSourceInterface
+   */
+  protected $fieldSource;
+
+  /**
+   * All CCK field info in the source database, keyed by node type.
+   *
+   * @var array
+   */
+  protected $fieldInfo;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, EntityManagerInterface $entity_manager, MigratePluginManager $source_plugins) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $entity_manager);
+    $this->fieldSource = $source_plugins->createInstance('d6_field', [], $migration);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $migration,
+      $container->get('entity.manager'),
+      $container->get('plugin.manager.migrate.source')
+    );
+  }
+
+  /**
    * {@inheritdoc}
    */
   public function query() {
@@ -115,10 +169,63 @@ public function prepareRow(Row $row) {
     if ($row->getSourceProperty('format') === '0') {
       $row->setSourceProperty('format', $this->filterDefaultFormat);
     }
+
+    $node_type = $row->getSourceProperty('type');
+    if (isset($this->fieldInfo[$node_type])) {
+      foreach ($this->fieldInfo[$node_type] as $field) {
+        // @TODO: Massage the field values so that field_foo_value becomes
+        // just 'value', and so forth.
+        $row->setSourceProperty($field['field_name'], $this->getFieldValues($field, $row));
+      }
+    }
+
     return parent::prepareRow($row);
   }
 
   /**
+   * Retrieves field values for a specific field of a single node.
+   *
+   * @param array $field_info
+   *   The field and field instance definition.
+   * @param \Drupal\migrate\Row $row
+   *   The current row (node).
+   *
+   * @return array
+   *   The raw field values from the database, keyed by delta.
+   */
+  protected function getFieldValues(array $field_info, Row $row) {
+    $field_table = 'content_field_' . $field_info['field_name'];
+    $node_table = 'content_type_' . $row->getSourceProperty('type');
+
+    if ($this->tableExists($field_table)) {
+      $query = $this->select($field_table, 't');
+    }
+    elseif ($this->tableExists($node_table)) {
+      $query = $this->select($node_table, 't');
+
+      // 0 AS delta. If the values are stored in the content_type_* table,
+      // they won't have a delta, so use a constant 0.
+      $query->addExpression(0, 'delta');
+
+      // Add the individual field columns.
+      foreach (array_keys($field_info['db_columns']) as $column) {
+        $query->addField('t', $column);
+      }
+    }
+
+    if (isset($query)) {
+      return $query
+        ->condition('nid', $row->getSourceProperty('nid'))
+        ->condition('vid', $row->getSourceProperty('vid'))
+        ->execute()
+        ->fetchAllAssoc('delta');
+    }
+    else {
+      return [];
+    }
+  }
+
+  /**
    * {@inheritdoc}
    */
   public function getIds() {
@@ -141,4 +248,45 @@ public function entityTypeId() {
     return 'node';
   }
 
+  /**
+   * Returns field and field instance definitions for all fields on a given
+   * node type.
+   *
+   * @param string $node_type
+   *   The node type to be queried.
+   *
+   * @return array
+   *   An array of field and field instance definition arrays from the source
+   *   database.
+   */
+  protected function getFieldInfo($node_type) {
+    if (!isset($this->fieldInfo)) {
+      $this->fieldInfo = [];
+      foreach ($this->fieldSource as $row) {
+        $this->fieldInfo[$row->getSourceProperty('type_name')][] = $row->getSource();
+      }
+    }
+    return @($this->fieldInfo[$node_type] ?: []);
+  }
+
+  /**
+   * Determines whether a specific CCK table exists.
+   */
+  protected function tableExists($table) {
+    if (!isset($this->tables[$table])) {
+      $this->tables[$table] = $this->cckSchemaCorrect() && $this->getDatabase()->schema()->tableExists($table);
+    }
+    return $this->tables[$table];
+  }
+
+  /**
+   * Determines whether CCK is enabled and is using the right schema.
+   */
+  protected function cckSchemaCorrect() {
+    if (!isset($this->cckSchemaCorrect)) {
+      $this->cckSchemaCorrect = $this->moduleExists('content') && $this->getModuleSchemaVersion('content') >= 6001;
+    }
+    return $this->cckSchemaCorrect;
+  }
+
 }
diff --git a/core/modules/migrate_drupal/tests/src/Unit/source/d6/NodeByNodeTypeTest.php b/core/modules/migrate_drupal/tests/src/Unit/source/d6/NodeByNodeTypeTest.php
index 2370bd8..fca3466 100644
--- a/core/modules/migrate_drupal/tests/src/Unit/source/d6/NodeByNodeTypeTest.php
+++ b/core/modules/migrate_drupal/tests/src/Unit/source/d6/NodeByNodeTypeTest.php
@@ -7,14 +7,12 @@
 
 namespace Drupal\Tests\migrate_drupal\Unit\source\d6;
 
-use Drupal\Tests\migrate\Unit\MigrateSqlSourceTestCase;
-
 /**
  * Tests D6 node source plugin with 'node_type' configuration.
  *
  * @group migrate_drupal
  */
-class NodeByNodeTypeTest extends MigrateSqlSourceTestCase {
+class NodeByNodeTypeTest extends NodeTestBase {
 
   const PLUGIN_CLASS = 'Drupal\migrate_drupal\Plugin\migrate\source\d6\Node';
 
diff --git a/core/modules/migrate_drupal/tests/src/Unit/source/d6/NodeRevisionByNodeTypeTest.php b/core/modules/migrate_drupal/tests/src/Unit/source/d6/NodeRevisionByNodeTypeTest.php
index e4e7acb..1943aa0 100644
--- a/core/modules/migrate_drupal/tests/src/Unit/source/d6/NodeRevisionByNodeTypeTest.php
+++ b/core/modules/migrate_drupal/tests/src/Unit/source/d6/NodeRevisionByNodeTypeTest.php
@@ -7,14 +7,12 @@
 
 namespace Drupal\Tests\migrate_drupal\Unit\source\d6;
 
-use Drupal\Tests\migrate\Unit\MigrateSqlSourceTestCase;
-
 /**
  * Tests D6 node revision source plugin.
  *
  * @group migrate_drupal
  */
-class NodeRevisionByNodeTypeTest extends MigrateSqlSourceTestCase {
+class NodeRevisionByNodeTypeTest extends NodeTestBase {
 
   const PLUGIN_CLASS = 'Drupal\migrate_drupal\Plugin\migrate\source\d6\NodeRevision';
 
diff --git a/core/modules/migrate_drupal/tests/src/Unit/source/d6/NodeRevisionTest.php b/core/modules/migrate_drupal/tests/src/Unit/source/d6/NodeRevisionTest.php
index 4dde4b1..8d21aea 100644
--- a/core/modules/migrate_drupal/tests/src/Unit/source/d6/NodeRevisionTest.php
+++ b/core/modules/migrate_drupal/tests/src/Unit/source/d6/NodeRevisionTest.php
@@ -7,14 +7,12 @@
 
 namespace Drupal\Tests\migrate_drupal\Unit\source\d6;
 
-use Drupal\Tests\migrate\Unit\MigrateSqlSourceTestCase;
-
 /**
  * Tests D6 node revision source plugin.
  *
  * @group migrate_drupal
  */
-class NodeRevisionTest extends MigrateSqlSourceTestCase {
+class NodeRevisionTest extends NodeTestBase {
 
   const PLUGIN_CLASS = 'Drupal\migrate_drupal\Plugin\migrate\source\d6\NodeRevision';
 
diff --git a/core/modules/migrate_drupal/tests/src/Unit/source/d6/NodeTest.php b/core/modules/migrate_drupal/tests/src/Unit/source/d6/NodeTest.php
index a108f61..65e8091 100644
--- a/core/modules/migrate_drupal/tests/src/Unit/source/d6/NodeTest.php
+++ b/core/modules/migrate_drupal/tests/src/Unit/source/d6/NodeTest.php
@@ -7,14 +7,12 @@
 
 namespace Drupal\Tests\migrate_drupal\Unit\source\d6;
 
-use Drupal\Tests\migrate\Unit\MigrateSqlSourceTestCase;
-
 /**
  * Tests D6 node source plugin.
  *
  * @group migrate_drupal
  */
-class NodeTest extends MigrateSqlSourceTestCase {
+class NodeTest extends NodeTestBase {
 
   const PLUGIN_CLASS = 'Drupal\migrate_drupal\Plugin\migrate\source\d6\Node';
 
diff --git a/core/modules/migrate_drupal/tests/src/Unit/source/d6/NodeTestBase.php b/core/modules/migrate_drupal/tests/src/Unit/source/d6/NodeTestBase.php
new file mode 100644
index 0000000..83168e7
--- /dev/null
+++ b/core/modules/migrate_drupal/tests/src/Unit/source/d6/NodeTestBase.php
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\migrate_drupal\Unit\source\d6\NodeTestBase.
+ */
+
+namespace Drupal\Tests\migrate_drupal\Unit\source\d6;
+
+use Drupal\Tests\migrate\Unit\MigrateSqlSourceTestCase;
+
+abstract class NodeTestBase extends MigrateSqlSourceTestCase {
+
+  /**
+   * Mocks plugin dependencies for tests which use the d6_node source.
+   *
+   * @return array
+   */
+  protected function getPluginDependencies() {
+    $dependencies = parent::getPluginDependencies();
+    $dependencies[] = $this->getMockBuilder('\Drupal\migrate\Plugin\MigratePluginManager')
+      ->disableOriginalConstructor()
+      ->getMock();
+
+    // Calling createInstance() should always return a mock source plugin.
+    end($dependencies)->method('createInstance')
+      ->willReturn($this->getMock('\Drupal\migrate\Plugin\MigrateSourceInterface'));
+
+    return $dependencies;
+  }
+
+}
