diff --git a/lib/Drupal/migrate/Plugin/migrate/source/d6/ProfileField.php b/lib/Drupal/migrate/Plugin/migrate/source/d6/ProfileField.php
new file mode 100644
index 0000000..cc75968
--- /dev/null
+++ b/lib/Drupal/migrate/Plugin/migrate/source/d6/ProfileField.php
@@ -0,0 +1,65 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Plugin\migrate\source\d6\ProfileField.
+ */
+
+namespace Drupal\migrate\Plugin\migrate\source\d6;
+
+use Drupal\migrate\Plugin\migrate\source\SqlBase;
+
+/**
+ * Drupal 6 profile fields source from database.
+ *
+ * @PluginId("drupal6_profile_field")
+ */
+class ProfileField extends SqlBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function query() {
+    $query = $this->database
+      ->select('profile_fields', 'pf')
+      ->fields('pf', array(
+        'fid',
+        'title',
+        'name',
+        'explanation',
+        'category',
+        'page',
+        'type',
+        'weight',
+        'required',
+        'register',
+        'visibility',
+        'autocomplete',
+        'options',
+      ));
+
+    return $query;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fields() {
+    return array(
+      'fid' => t('Primary Key: Unique profile field ID.'),
+      'title' => t('Title of the field shown to the end user.'),
+      'name' => t('Internal name of the field used in the form HTML and URLs.'),
+      'explanation' => t('Explanation of the field to end users.'),
+      'category' => t('Profile category that the field will be grouped under.'),
+      'page' => t("Title of page used for browsing by the field's value"),
+      'type' => t('Type of form field.'),
+      'weight' => t('Weight of field in relation to other profile fields.'),
+      'required' => t('Whether the user is required to enter a value. (0 = no, 1 = yes)'),
+      'register' => t('Whether the field is visible in the user registration form. (1 = yes, 0 = no)'),
+      'visibility' => t('The level of visibility for the field. (0 = hidden, 1 = private, 2 = public on profile but not member list pages, 3 = public on profile and list pages)'),
+      'autocomplete' => t('Whether form auto-completion is enabled. (0 = disabled, 1 = enabled)'),
+      'options' => t('List of options to be used in a list selection field.'),
+    );
+  }
+
+}
diff --git a/tests/Drupal/migrate/Tests/D6ProfileFieldSourceTest.php b/tests/Drupal/migrate/Tests/D6ProfileFieldSourceTest.php
new file mode 100644
index 0000000..554d5b2
--- /dev/null
+++ b/tests/Drupal/migrate/Tests/D6ProfileFieldSourceTest.php
@@ -0,0 +1,115 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\migrate\Tests\D6ProfileFieldSourceTest.
+ */
+
+namespace Drupal\migrate\Tests;
+
+/**
+ * Tests Profile fields migration from D6 to D8.
+ *
+ * @group migrate
+ */
+class D6ProfileFieldsSourceTest extends MigrateSqlSourceTestCase {
+
+  // The plugin system is not working during unit testing so the source plugin
+  // class needs to be manually specified.
+  const PLUGIN_CLASS = 'Drupal\migrate\Plugin\migrate\source\d6\ProfileField';
+
+  // The fake Migration configuration entity.
+  protected $migrationConfiguration = array(
+    // The id of the entity, can be any string.
+    'id' => 'test_profile_fields',
+    // Leave it empty for now.
+    'idlist' => array(),
+    'source' => array(
+      'plugin' => 'drupal6_profile_field',
+    ),
+    // This needs to be the identifier of the actual key: cid for comment, nid
+    // for node and so on.
+    'sourceIds' => array(
+      'fid' => array(
+        // This is where the field schema would go but for now we need to
+        // specify the table alias for the key. Most likely this will be the
+        // same as BASE_ALIAS.
+        'alias' => 'pf',
+      ),
+    ),
+    'destinationIds' => array(
+      'profilefield' => array(
+        // This is where the field schema would go.
+      ),
+    ),
+  );
+
+  // We need to set up the database contents; it's easier to do that below.
+  // These are sample result queries.
+  //TODO: Add multiple cases
+  protected $results = array(
+    array(
+      'fid' => 1,
+      'title' => 'First name',
+      'name' => 'profile_first_name',
+      'explanation' => 'First name user',
+      'category' => 'profile',
+      'page' => '',
+      'type' => 'textfield',
+      'weight' => 0,
+      'required' => 1,
+      'register' => 0,
+      'visibility' => 2,
+      'autocomplete' => 0,
+      'options' => '',
+    ),
+      'fid' => 2,
+      'title' => 'Last name',
+      'name' => 'profile_last_name',
+      'explanation' => 'Last name user',
+      'category' => 'profile',
+      'page' => '',
+      'type' => 'textfield',
+      'weight' => 0,
+      'required' => 0,
+      'register' => 0,
+      'visibility' => 2,
+      'autocomplete' => 0,
+      'options' => '',
+    ),
+      'fid' => 3,
+      'title' => 'Policy',
+      'name' => 'profile_policy',
+      'explanation' => 'A checkbox that say if you accept policy of website',
+      'category' => 'profile',
+      'page' => '',
+      'type' => 'checkbox',
+      'weight' => 0,
+      'required' => 1,
+      'register' => 1,
+      'visibility' => 2,
+      'autocomplete' => 0,
+      'options' => '',
+    ),
+  );
+
+  /**
+   * Prepopulate contents with results.
+   */
+  public function setUp() {
+    $this->databaseContents['profile_fields'] = $this->results;
+    parent::setUp();
+  }
+
+  /**
+   * Provide meta information about this battery of tests.
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'D6 profile field source functionality',
+      'description' => 'Tests D6 profile field source plugin.',
+      'group' => 'Migrate',
+    );
+  }
+
+}
