diff --git a/src/Feeds/Target/ConfigEntityReference.php b/src/Feeds/Target/ConfigEntityReference.php
new file mode 100644
index 00000000..68f1bbb4
--- /dev/null
+++ b/src/Feeds/Target/ConfigEntityReference.php
@@ -0,0 +1,324 @@
+<?php
+
+namespace Drupal\feeds\Feeds\Target;
+
+use Drupal\Core\Config\Entity\ConfigEntityInterface;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Entity\EntityRepositoryInterface;
+use Drupal\Core\Field\FieldDefinitionInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Language\LanguageInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\Transliteration\PhpTransliteration;
+use Drupal\feeds\Exception\EmptyFeedException;
+use Drupal\feeds\Exception\ReferenceNotFoundException;
+use Drupal\feeds\Exception\TargetValidationException;
+use Drupal\feeds\FeedInterface;
+use Drupal\feeds\FieldTargetDefinition;
+use Drupal\feeds\Plugin\Type\Target\ConfigurableTargetInterface;
+use Drupal\feeds\Plugin\Type\Target\FieldTargetBase;
+use Drupal\feeds\StateInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Defines a config entity reference mapper.
+ *
+ * @FeedsTarget(
+ *   id = "config_entity_reference",
+ *   field_types = {"entity_reference"},
+ * )
+ */
+class ConfigEntityReference extends FieldTargetBase implements ConfigurableTargetInterface, ContainerFactoryPluginInterface {
+
+  /**
+   * The entity type manager.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+   */
+  protected $entityTypeManager;
+
+  /**
+   * The entity repository service.
+   *
+   * @var \Drupal\Core\Entity\EntityRepositoryInterface
+   */
+  protected $entityRepository;
+
+  /**
+   * The transliteration manager.
+   *
+   * @var \Drupal\Core\Transliteration\PhpTransliteration
+   */
+  protected $transliteration;
+
+  /**
+   * Constructs a ConfigEntityReference object.
+   *
+   * @param array $configuration
+   *   The plugin configuration.
+   * @param string $plugin_id
+   *   The plugin id.
+   * @param array $plugin_definition
+   *   The plugin definition.
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
+   *   The entity type manager.
+   * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
+   *   The entity repository service.
+   * @param \Drupal\Core\Transliteration\PhpTransliteration $transliteration
+   *   The transliteration manager.
+   */
+  public function __construct(array $configuration, $plugin_id, array $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityRepositoryInterface $entity_repository, PhpTransliteration $transliteration) {
+    $this->entityTypeManager = $entity_type_manager;
+    $this->entityRepository = $entity_repository;
+    $this->transliteration = $transliteration;
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get('entity_type.manager'),
+      $container->get('entity.repository'),
+      $container->get('transliteration')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static function prepareTarget(FieldDefinitionInterface $field_definition) {
+    $type = $field_definition->getSetting('target_type');
+    if (!\Drupal::entityTypeManager()->getDefinition($type)->entityClassImplements(ConfigEntityInterface::class)) {
+      return;
+    }
+
+    return FieldTargetDefinition::createFromFieldDefinition($field_definition)
+      ->addProperty('target_id');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setTarget(FeedInterface $feed, EntityInterface $entity, $field_name, array $raw_values) {
+    $values = [];
+    foreach ($raw_values as $delta => $columns) {
+      try {
+        $this->prepareValue($delta, $columns);
+        $values[] = $columns;
+      }
+      catch (ReferenceNotFoundException $e) {
+        // The referenced entity is not found. We need to enforce Feeds to try
+        // to import the same item again on the next import.
+        // Feeds stores a hash of every imported item in order to make the
+        // import process more efficient by ignoring items it has already seen.
+        // In this case we need to destroy the hash in order to be able to
+        // import the reference on a next import.
+        $entity->get('feeds_item')->hash = NULL;
+        $feed->getState(StateInterface::PROCESS)->setMessage($e->getFormattedMessage(), 'warning', TRUE);
+      }
+      catch (EmptyFeedException $e) {
+        // Nothing wrong here.
+      }
+      catch (TargetValidationException $e) {
+        // Validation failed.
+        $this->addMessage($e->getFormattedMessage(), 'error');
+      }
+    }
+
+    if (!empty($values)) {
+      $entity_target = $this->getEntityTarget($feed, $entity);
+      if ($entity_target) {
+        $item_list = $entity_target->get($field_name);
+
+        // Append these values to the existing values.
+        $values = array_merge($item_list->getValue(), $values);
+
+        $item_list->setValue($values);
+      }
+    }
+  }
+
+  /**
+   * Returns possible fields to reference by for a config entity.
+   *
+   * @return array
+   *   A list of fields to reference by.
+   */
+  protected function getPotentialFields() {
+    /** @var \Drupal\Core\Config\Entity\ConfigEntityTypeInterface $config_entity_type */
+    $config_entity_type = $this->entityTypeManager->getDefinition($this->getEntityType());
+    $config_name = $config_entity_type->getConfigPrefix() . '.*';
+    $definition = \Drupal::service('config.typed')->getDefinition($config_name);
+
+    if (!empty($definition['mapping'])) {
+      $options = [];
+      foreach ($definition['mapping'] as $key => $mapper) {
+        switch ($mapper['type']) {
+          case 'integer':
+          case 'label':
+          case 'string':
+          case 'text':
+          case 'uuid':
+            $options[$key] = $mapper['label'];
+            break;
+        }
+      }
+      return $options;
+    }
+
+    return [
+      'id' => $this->t('ID'),
+      'uuid' => $this->t('UUID'),
+    ];
+  }
+
+  /**
+   * Returns the entity type that can be referenced.
+   *
+   * @return string
+   *   The entity type being referenced.
+   */
+  protected function getEntityType() {
+    return $this->settings['target_type'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function prepareValue($delta, array &$values) {
+    // Check if there is a value for target ID.
+    if (!isset($values['target_id']) || strlen(trim($values['target_id'])) === 0) {
+      // No value.
+      throw new EmptyFeedException();
+    }
+
+    if ($target_id = $this->findEntity($values['target_id'], $this->configuration['reference_by'])) {
+      $values['target_id'] = $target_id;
+      return;
+    }
+
+    throw new ReferenceNotFoundException($this->t('Referenced entity not found for field %field with value %target_id.', [
+      '%target_id' => $values['target_id'],
+      '%field' => $this->configuration['reference_by'],
+    ]));
+  }
+
+  /**
+   * Searches for an entity by entity key.
+   *
+   * @param string $value
+   *   The value to search for.
+   * @param string $field
+   *   The subfield to search in.
+   *
+   * @return int|bool
+   *   The entity id, or false, if not found.
+   */
+  protected function findEntity($value, $field) {
+    switch ($field) {
+      case 'uuid':
+        if (NULL !== ($entity = $this->entityRepository->loadEntityByUuid($this->getEntityType(), $value))) {
+          return $entity->id();
+        }
+        break;
+
+      default:
+        $ids = $this->entityTypeManager->getStorage($this->getEntityType())
+          ->getQuery()
+          ->condition($field, $value)
+          ->range(0, 1)
+          ->execute();
+
+        if ($ids) {
+          return reset($ids);
+        }
+    }
+
+    return FALSE;
+  }
+
+  /**
+   * Generates a machine name from a string.
+   *
+   * This is basically the same as what is done in
+   * \Drupal\Core\Block\BlockBase::getMachineNameSuggestion() and
+   * \Drupal\system\MachineNameController::transliterate(), but it seems
+   * that so far there is no common service for handling this.
+   *
+   * @param string $string
+   *   The string to generate a machine name for.
+   *
+   * @return string
+   *   The generated machine name.
+   *
+   * @see \Drupal\Core\Block\BlockBase::getMachineNameSuggestion()
+   * @see \Drupal\system\MachineNameController::transliterate()
+   */
+  protected function generateMachineName($string) {
+    $transliterated = $this->transliteration->transliterate($string, LanguageInterface::LANGCODE_DEFAULT, '_');
+    $transliterated = mb_strtolower($transliterated);
+
+    $transliterated = preg_replace('@[^a-z0-9_.]+@', '_', $transliterated);
+
+    return $transliterated;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function defaultConfiguration() {
+    $config = [
+      'reference_by' => 'id',
+    ];
+    return $config;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
+    $options = $this->getPotentialFields();
+
+    // Hack to find out the target delta.
+    foreach ($form_state->getValues() as $key => $value) {
+      if (strpos($key, 'target-settings-') === 0) {
+        list(, , $delta) = explode('-', $key);
+        break;
+      }
+    }
+
+    $form['reference_by'] = [
+      '#type' => 'select',
+      '#title' => $this->t('Reference by'),
+      '#options' => $options,
+      '#default_value' => $this->configuration['reference_by'],
+    ];
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getSummary() {
+    $options = $this->getPotentialFields();
+
+    $summary = [];
+
+    if ($this->configuration['reference_by'] && isset($options[$this->configuration['reference_by']])) {
+      $summary[] = $this->t('Reference by: %message', ['%message' => $options[$this->configuration['reference_by']]]);
+    }
+    else {
+      $summary[] = $this->t('Please select a field to reference by.');
+    }
+
+    return $summary;
+  }
+
+}
diff --git a/src/Feeds/Target/UserRole.php b/src/Feeds/Target/UserRole.php
new file mode 100644
index 00000000..191b2da1
--- /dev/null
+++ b/src/Feeds/Target/UserRole.php
@@ -0,0 +1,222 @@
+<?php
+
+namespace Drupal\feeds\Feeds\Target;
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\feeds\FeedInterface;
+use Drupal\feeds\FeedTypeInterface;
+use Drupal\feeds\Plugin\Type\Processor\EntityProcessorInterface;
+use Drupal\user\RoleInterface;
+
+/**
+ * Defines a user role mapper.
+ *
+ * @FeedsTarget(
+ *   id = "user_role",
+ * )
+ */
+class UserRole extends ConfigEntityReference {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function targets(array &$targets, FeedTypeInterface $feed_type, array $definition) {
+    $processor = $feed_type->getProcessor();
+
+    if (!$processor instanceof EntityProcessorInterface) {
+      return $targets;
+    }
+
+    $field_definitions = \Drupal::service('entity_field.manager')->getFieldDefinitions($processor->entityType(), $processor->bundle());
+
+    foreach ($field_definitions as $id => $field_definition) {
+      if ($field_definition->getType() == 'entity_reference' && $field_definition->getSetting('target_type') == 'user_role') {
+        if ($target = static::prepareTarget($field_definition)) {
+          $target->setPluginId($definition['id']);
+          $targets[$id] = $target;
+        }
+      }
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setTarget(FeedInterface $feed, EntityInterface $entity, $field_name, array $values) {
+    // Check if values list is currently empty.
+    $entity_target = $this->getEntityTarget($feed, $entity);
+    $is_empty = empty($entity_target->get($field_name)->getValue());
+
+    if (empty($entity_target)) {
+      return;
+    }
+
+    parent::setTarget($feed, $entity, $field_name, $values);
+
+    $item_list = $entity_target->get($field_name);
+
+    // Append roles from unsaved entity, if there is one.
+    if ($entity_target->id() && $is_empty) {
+      $original = $this->entityTypeManager->getStorage($entity_target->getEntityTypeId())
+        ->loadUnchanged($entity->id());
+      if ($original) {
+        $original_values = $original->get($field_name)->getValue();
+
+        // Revoke roles, when that option is enabled. But do not touch roles
+        // that are not allowed to set by the source.
+        if ($this->configuration['revoke_roles']) {
+          foreach ($original_values as $key => $value) {
+            $rid = $value['target_id'];
+            if (!empty($this->configuration['allowed_roles'][$rid])) {
+              unset($original_values[$key]);
+            }
+          }
+        }
+
+        // Merge the remaining values.
+        $values = array_merge($item_list->getValue(), $original_values);
+
+        $item_list->setValue($values);
+      }
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function findEntity($value, $field) {
+    $entity_id = parent::findEntity($value, $field);
+    if ($entity_id !== FALSE) {
+      // Check if the role may be assigned.
+      if (isset($this->configuration['allowed_roles'][$entity_id]) && !$this->configuration['allowed_roles'][$entity_id]) {
+        // This role may *not* be assiged.
+        return FALSE;
+      }
+
+      return $entity_id;
+    }
+
+    // Automatically create a new role.
+    if ($this->configuration['autocreate'] && in_array($this->configuration['reference_by'], ['id', 'name'])) {
+      return $this->createRole($value);
+    }
+  }
+
+  /**
+   * Creates a new role with the given label and saves it.
+   *
+   * @param string $label
+   *   The label the new role should get.
+   *
+   * @return int|string|false
+   *   The ID of the new role or false if the given label is empty.
+   */
+  protected function createRole($label) {
+    if (!strlen(trim($label))) {
+      return FALSE;
+    }
+
+    $values = [
+      'id' => $this->generateMachineName($label),
+      'name' => $label,
+    ];
+    $entity = $this->entityTypeManager->getStorage($this->getEntityType())->create($values);
+
+    $entity->save();
+
+    return $entity->id();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function defaultConfiguration() {
+    $role_names = array_keys($this->getRoleNames());
+
+    $config = parent::defaultConfiguration() + [
+      'allowed_roles' => array_combine($role_names, $role_names),
+      'autocreate' => FALSE,
+      'revoke_roles' => FALSE,
+    ];
+    return $config;
+  }
+
+  /**
+   * Returns a list of role names, keyed by role ID.
+   *
+   * @return array
+   *   A list of role names.
+   */
+  protected function getRoleNames() {
+    $roles = $this->entityTypeManager->getStorage('user_role')->loadMultiple();
+    unset($roles[RoleInterface::ANONYMOUS_ID]);
+    unset($roles[RoleInterface::AUTHENTICATED_ID]);
+
+    return array_map(function ($item) {
+      return $item->label();
+    }, $roles);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
+    $form = parent::buildConfigurationForm($form, $form_state);
+
+    $form['allowed_roles'] = [
+      '#type' => 'checkboxes',
+      '#title' => $this->t('Allowed roles'),
+      '#options' => $this->getRoleNames(),
+      '#default_value' => $this->configuration['allowed_roles'],
+      '#description' => $this->t('Select the roles to accept from the feed.<br />Any other roles will be ignored.'),
+    ];
+    $form['autocreate'] = [
+      '#type' => 'checkbox',
+      '#title' => $this->t('Auto create'),
+      '#description' => $this->t("Create the role if it doesn't exist."),
+      '#default_value' => $this->configuration['autocreate'],
+    ];
+    $form['revoke_roles'] = [
+      '#type' => 'checkbox',
+      '#title' => $this->t('Revoke roles'),
+      '#description' => t('If enabled, roles that are not provided by the feed will be revoked for the user. This affects only the "Allowed roles" as configured above.'),
+      '#default_value' => $this->configuration['revoke_roles'],
+    ];
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getSummary() {
+    $summary = parent::getSummary();
+
+    // Allowed roles.
+    $role_names = array_intersect_key($this->getRoleNames(), array_filter($this->configuration['allowed_roles']));
+    if (empty($role_names)) {
+      $role_names = ['<' . $this->t('none') . '>'];
+    }
+    $summary[] = $this->t('Allowed roles: %roles', ['%roles' => implode(', ', $role_names)]);
+
+    // Autocreate.
+    if ($this->configuration['autocreate']) {
+      $summary[] = $this->t('Automatically create roles');
+    }
+    else {
+      $summary[] = $this->t('Only assign existing roles');
+    }
+
+    // Revoke roles.
+    if ($this->configuration['revoke_roles']) {
+      $summary[] = $this->t('Revoke roles: yes');
+    }
+    else {
+      $summary[] = $this->t('Revoke roles: no');
+    }
+
+    return $summary;
+  }
+
+}
diff --git a/src/Plugin/Type/Target/FieldTargetBase.php b/src/Plugin/Type/Target/FieldTargetBase.php
index c00d7ec2..331753ee 100644
--- a/src/Plugin/Type/Target/FieldTargetBase.php
+++ b/src/Plugin/Type/Target/FieldTargetBase.php
@@ -47,6 +47,9 @@ abstract class FieldTargetBase extends TargetBase implements ConfigurableTargetI
     $field_definitions = \Drupal::service('entity_field.manager')->getFieldDefinitions($processor->entityType(), $processor->bundle());
 
     foreach ($field_definitions as $id => $field_definition) {
+      if (isset($targets[$id])) {
+        continue;
+      }
       if ($id === $processor->bundleKey()) {
         continue;
       }
diff --git a/tests/modules/feeds_test_alter_source/feeds_test_alter_source.services.yml b/tests/modules/feeds_test_alter_source/feeds_test_alter_source.services.yml
index dcc565f8..d6031f8c 100644
--- a/tests/modules/feeds_test_alter_source/feeds_test_alter_source.services.yml
+++ b/tests/modules/feeds_test_alter_source/feeds_test_alter_source.services.yml
@@ -3,3 +3,8 @@ services:
     class: Drupal\feeds_test_alter_source\EventSubscriber\CsvFeed
     tags:
       - {name: event_subscriber}
+
+  feeds_test_alter_source.user_feed:
+    class: Drupal\feeds_test_alter_source\EventSubscriber\UserFeed
+    tags:
+      - {name: event_subscriber}
diff --git a/tests/modules/feeds_test_alter_source/src/EventSubscriber/UserFeed.php b/tests/modules/feeds_test_alter_source/src/EventSubscriber/UserFeed.php
new file mode 100644
index 00000000..5ba9be46
--- /dev/null
+++ b/tests/modules/feeds_test_alter_source/src/EventSubscriber/UserFeed.php
@@ -0,0 +1,46 @@
+<?php
+
+namespace Drupal\feeds_test_alter_source\EventSubscriber;
+
+use Drupal\feeds\Event\FeedsEvents;
+use Drupal\feeds\Event\ParseEvent;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+/**
+ * Alters the parsed result for the feeds importing users.
+ */
+class UserFeed implements EventSubscriberInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getSubscribedEvents() {
+    return [
+      FeedsEvents::PARSE => [
+        ['afterParse', FeedsEvents::AFTER],
+      ],
+    ];
+  }
+
+  /**
+   * Acts on parser result.
+   */
+  public function afterParse(ParseEvent $event) {
+    if ($event->getFeed()->getType()->id() != 'user_import') {
+      // Not interested in this feed. Abort.
+      return;
+    }
+
+    /** @var \Drupal\feeds\Feeds\Item\ItemInterface $item */
+    foreach ($event->getParserResult() as $item) {
+      // Convert roles value to multiple values.
+      foreach (['role_ids', 'role_labels'] as $source_name) {
+        $data = $item->get($source_name);
+        if (!empty($data)) {
+          $item->set($source_name, explode('|', $data));
+        }
+      }
+    }
+  }
+
+}
diff --git a/tests/resources/csv/content-with-config-reference.csv b/tests/resources/csv/content-with-config-reference.csv
new file mode 100644
index 00000000..9fc78a83
--- /dev/null
+++ b/tests/resources/csv/content-with-config-reference.csv
@@ -0,0 +1,3 @@
+"guid","title","type"
+1,"Eodem modo typi","test"
+2,"Aliquam feugiat diam","test2"
diff --git a/tests/resources/csv/users_roles.csv b/tests/resources/csv/users_roles.csv
new file mode 100644
index 00000000..0862b625
--- /dev/null
+++ b/tests/resources/csv/users_roles.csv
@@ -0,0 +1,5 @@
+name,mail,since,password,role_ids,role_labels
+Morticia,morticia@example.com,1244347500,mort,editor,"Article Editor"
+Fester,fester@example.com,1241865600,fest,manager,"Account Manager"
+Gomez,gomez@example.com,1228572000,gome,tester| |manager,"Software Tester| |Account Manager"
+Pugsley,pugsley@example.com,1228260225,pugs,,
\ No newline at end of file
diff --git a/tests/src/Kernel/Feeds/Target/ConfigEntityReferenceTest.php b/tests/src/Kernel/Feeds/Target/ConfigEntityReferenceTest.php
new file mode 100644
index 00000000..d0127142
--- /dev/null
+++ b/tests/src/Kernel/Feeds/Target/ConfigEntityReferenceTest.php
@@ -0,0 +1,189 @@
+<?php
+
+namespace Drupal\Tests\feeds\Kernel\Feeds\Target;
+
+use Drupal\node\Entity\Node;
+use Drupal\entity_test\Entity\EntityTestBundle;
+use Drupal\feeds\Event\FeedsEvents;
+use Drupal\feeds\Event\ParseEvent;
+use Drupal\Tests\feeds\Kernel\FeedsKernelTestBase;
+use Drupal\Tests\field\Traits\EntityReferenceTestTrait;
+
+/**
+ * Tests for the config entity reference target.
+ *
+ * @group feeds
+ */
+class ConfigEntityReferenceTest extends FeedsKernelTestBase {
+
+  use EntityReferenceTestTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = [
+    'field',
+    'node',
+    'feeds',
+    'text',
+    'filter',
+    'entity_test',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    // Create two config entities.
+    EntityTestBundle::create([
+      'id' => 'test',
+      'label' => 'Lorem',
+      'description' => 'My test description',
+    ])->save();
+
+    EntityTestBundle::create([
+      'id' => 'test2',
+      'label' => 'Ut wisi',
+      'description' => 'My test2 description',
+    ])->save();
+
+    // Create a config entity reference field.
+    $this->createEntityReferenceField('node', 'article', 'field_entity_test_type', 'Type', 'entity_test_bundle');
+  }
+
+  /**
+   * Tests importing config entity references by ID.
+   */
+  public function testImportById() {
+    // Create a feed type, map to created field.
+    $feed_type = $this->createFeedTypeForCsv([
+      'guid' => 'guid',
+      'title' => 'title',
+      'type' => 'type',
+    ], [
+      'mappings' => array_merge($this->getDefaultMappings(), [
+        [
+          'target' => 'field_entity_test_type',
+          'map' => ['target_id' => 'type'],
+          'settings' => ['reference_by' => 'id'],
+        ],
+      ]),
+    ]);
+
+    // Import.
+    $feed = $this->createFeed($feed_type->id(), [
+      'source' => $this->resourcesPath() . '/csv/content-with-config-reference.csv',
+    ]);
+    $feed->import();
+
+    // Assert two created nodes.
+    $this->assertNodeCount(2);
+
+    // Test target id values of these nodes.
+    $expected_values = [
+      1 => 'test',
+      2 => 'test2',
+    ];
+    foreach ($expected_values as $nid => $expected_value) {
+      $node = Node::load($nid);
+      $this->assertEquals($expected_value, $node->field_entity_test_type->target_id);
+    }
+  }
+
+  /**
+   * Tests importing config entity references by label.
+   */
+  public function testImportByLabel() {
+    // Create a feed type, map to created field.
+    $feed_type = $this->createFeedTypeForCsv([
+      'guid' => 'guid',
+      'title' => 'title',
+      'alpha' => 'alpha',
+    ], [
+      'mappings' => array_merge($this->getDefaultMappings(), [
+        [
+          'target' => 'field_entity_test_type',
+          'map' => ['target_id' => 'alpha'],
+          'settings' => ['reference_by' => 'label'],
+        ],
+      ]),
+    ]);
+
+    // Import.
+    $feed = $this->createFeed($feed_type->id(), [
+      'source' => $this->resourcesPath() . '/csv/content.csv',
+    ]);
+    $feed->import();
+
+    // Assert two created nodes.
+    $this->assertNodeCount(2);
+
+    // Test target id values of these nodes.
+    $expected_values = [
+      1 => 'test',
+      2 => 'test2',
+    ];
+    foreach ($expected_values as $nid => $expected_value) {
+      $node = Node::load($nid);
+      $this->assertEquals($expected_value, $node->field_entity_test_type->target_id);
+    }
+  }
+
+  /**
+   * Tests importing config entity references by UUID.
+   */
+  public function testImportByUuid() {
+    // Because it's unpredictable which uuids a config entity gets, let's add an
+    // event subscriber that sets these values for the 'type' column.
+    $this->container->get('event_dispatcher')
+      ->addListener(FeedsEvents::PARSE, function (ParseEvent $event) {
+        // Set UUID on items.
+        $counter = 0;
+        $config_entities = ['test', 'test2'];
+        foreach ($event->getParserResult() as $item) {
+          $uuid = $this->entityTypeManager->getStorage('entity_test_bundle')
+            ->load($config_entities[$counter])
+            ->uuid();
+          $item->set('type', $uuid);
+          $counter++;
+        }
+      }, FeedsEvents::AFTER);
+
+    // Create a feed type, map to created field.
+    $feed_type = $this->createFeedTypeForCsv([
+      'guid' => 'guid',
+      'title' => 'title',
+      'type' => 'type',
+    ], [
+      'mappings' => array_merge($this->getDefaultMappings(), [
+        [
+          'target' => 'field_entity_test_type',
+          'map' => ['target_id' => 'type'],
+          'settings' => ['reference_by' => 'uuid'],
+        ],
+      ]),
+    ]);
+
+    // Import.
+    $feed = $this->createFeed($feed_type->id(), [
+      'source' => $this->resourcesPath() . '/csv/content.csv',
+    ]);
+    $feed->import();
+
+    // Assert two created nodes.
+    $this->assertNodeCount(2);
+
+    // Test target id values of these nodes.
+    $expected_values = [
+      1 => 'test',
+      2 => 'test2',
+    ];
+    foreach ($expected_values as $nid => $expected_value) {
+      $node = Node::load($nid);
+      $this->assertEquals($expected_value, $node->field_entity_test_type->target_id);
+    }
+  }
+
+}
diff --git a/tests/src/Kernel/Feeds/Target/UserRoleTest.php b/tests/src/Kernel/Feeds/Target/UserRoleTest.php
new file mode 100644
index 00000000..8119e63a
--- /dev/null
+++ b/tests/src/Kernel/Feeds/Target/UserRoleTest.php
@@ -0,0 +1,464 @@
+<?php
+
+namespace Drupal\Tests\feeds\Kernel\Feeds\Target;
+
+use Drupal\feeds\Plugin\Type\Processor\ProcessorInterface;
+use Drupal\Tests\feeds\Kernel\FeedsKernelTestBase;
+use Drupal\user\UserInterface;
+
+/**
+ * @coversDefaultClass \Drupal\feeds\Feeds\Target\UserRole
+ * @group feeds
+ */
+class UserRoleTest extends FeedsKernelTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = [
+    'field',
+    'user',
+    'feeds',
+    'feeds_test_alter_source',
+  ];
+
+  /**
+   * The feed type.
+   *
+   * @var \Drupal\feeds\FeedTypeInterface
+   */
+  protected $feedType;
+
+  /**
+   * The user storage.
+   *
+   * @var \Drupal\user\UserStorageInterface
+   */
+  protected $userStorage;
+
+  /**
+   * The role storage.
+   *
+   * @var \Drupal\user\RoleStorageInterface
+   */
+  protected $roleStorage;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->installEntitySchema('user');
+
+    // Create feed type.
+    $this->feedType = $this->createFeedTypeForCsv([
+      'name' => 'name',
+      'mail' => 'mail',
+      'role_ids' => 'role_ids',
+      'role_labels' => 'role_labels',
+    ], [
+      'id' => 'user_import',
+      'processor' => 'entity:user',
+      'processor_configuration' => [
+        'update_existing' => ProcessorInterface::UPDATE_EXISTING,
+        'authorize' => FALSE,
+      ],
+      'mappings' => [
+        [
+          'target' => 'name',
+          'map' => ['value' => 'name'],
+        ],
+        [
+          'target' => 'mail',
+          'map' => ['value' => 'mail'],
+          'unique' => ['value' => TRUE],
+        ],
+      ],
+    ]);
+
+    $this->userStorage = $this->container->get('entity_type.manager')->getStorage('user');
+    $this->roleStorage = $this->container->get('entity_type.manager')->getStorage('user_role');
+  }
+
+  /**
+   * Asserts that the given user has the given role.
+   *
+   * @param \Drupal\user\UserInterface $account
+   *   The account to check for the role.
+   * @param string $rid
+   *   The expected role ID that the user should have.
+   * @param string $message
+   *   (optional) Assertion message.
+   */
+  protected function assertHasRole(UserInterface $account, $rid, $message = '') {
+    $this->assertTrue($account->hasRole($rid), $message);
+  }
+
+  /**
+   * Asserts that the given user NOT has the given role.
+   *
+   * @param \Drupal\user\UserInterface $account
+   *   The account to check for the role.
+   * @param string $rid
+   *   The expected role ID that the user should NOT have.
+   * @param string $message
+   *   (optional) Assertion message.
+   */
+  protected function assertNotHasRole(UserInterface $account, $rid, $message = '') {
+    $this->assertFalse($account->hasRole($rid), $message);
+  }
+
+  /**
+   * Asserts the expected number of roles an user has.
+   *
+   * This excludes the authenticated user role.
+   *
+   * @param int $expected_number_of_roles
+   *   The expected number of roles.
+   * @param \Drupal\user\UserInterface $account
+   *   The account to check for the role count.
+   * @param string $message
+   *   (optional) Assertion message.
+   */
+  protected function assertRoleCount($expected_number_of_roles, UserInterface $account, $message = '') {
+    $this->assertEquals($expected_number_of_roles, count($account->getRoles(TRUE)), $message);
+  }
+
+  /**
+   * Tests mapping to role without automatically creating new roles.
+   */
+  public function testWithoutRoleCreation() {
+    // Create the manager role.
+    $this->createRole([], 'manager');
+
+    // Add mapping to role.
+    $this->feedType->addMapping([
+      'target' => 'roles',
+      'map' => ['target_id' => 'role_ids'],
+    ]);
+    $this->feedType->save();
+
+    // Import.
+    $feed = $this->createFeed($this->feedType->id(), [
+      'source' => $this->resourcesPath() . '/csv/users_roles.csv',
+    ]);
+    $feed->import();
+
+    // Assert that Morticia did not get any roles.
+    $account = user_load_by_name('Morticia');
+    $this->assertNotHasRole($account, 'editor', 'Morticia does not have the editor role.');
+    $this->assertRoleCount(0, $account, 'Morticia has no special roles.');
+
+    // Assert that Fester got the manager role and one role in total.
+    $account = user_load_by_name('Fester');
+    $this->assertHasRole($account, 'manager', 'Fester has the manager role.');
+    $this->assertRoleCount(1, $account, 'Fester has one role.');
+
+    // Assert that Gomez got the manager role but not the tester role, since
+    // that role doesn't exist on the system.
+    $account = user_load_by_name('Gomez');
+    $this->assertHasRole($account, 'manager', 'Gomez has the manager role.');
+    $this->assertNotHasRole($account, 'tester', 'Gomez does not have the tester role.');
+    $this->assertRoleCount(1, $account, 'Gomez has one role.');
+
+    // Assert that Pugsley has no roles.
+    $account = user_load_by_name('Pugsley');
+    $this->assertRoleCount(0, $account, 'Pugsley has no special roles.');
+
+    // Assert that only one role exists:
+    // - manager.
+    $roles = $this->roleStorage->loadMultiple();
+    $this->assertEquals(1, count($roles), 'Only one role exists.');
+  }
+
+  /**
+   * Tests mapping to role with automatically creating new roles.
+   */
+  public function testWithRoleCreation() {
+    // Create the manager role.
+    $this->createRole([], 'manager');
+
+    // Add mapping to role.
+    $this->feedType->addMapping([
+      'target' => 'roles',
+      'map' => ['target_id' => 'role_ids'],
+      'settings' => [
+        'autocreate' => TRUE,
+      ],
+    ]);
+    $this->feedType->save();
+
+    // Import CSV file.
+    $feed = $this->createFeed($this->feedType->id(), [
+      'source' => $this->resourcesPath() . '/csv/users_roles.csv',
+    ]);
+    $feed->import();
+
+    // Assert that Morticia got the editor role and one role in total.
+    $account = user_load_by_name('Morticia');
+    $this->assertHasRole($account, 'editor', 'Morticia has the editor role.');
+    $this->assertRoleCount(1, $account, 'Morticia has one role.');
+
+    // Assert that Fester got the manager role and one role in total.
+    $account = user_load_by_name('Fester');
+    $this->assertHasRole($account, 'manager', 'Fester has the manager role.');
+    $this->assertRoleCount(1, $account, 'Fester has one role.');
+
+    // Assert that Gomez got the manager, the editor role and two roles in
+    // total.
+    $account = user_load_by_name('Gomez');
+    $this->assertHasRole($account, 'manager', 'Gomez has the manager role.');
+    $this->assertHasRole($account, 'tester', 'Gomez has the tester role.');
+    $this->assertRoleCount(2, $account, 'Gomez has two roles.');
+
+    // Assert that Pugsley has no roles.
+    $account = user_load_by_name('Pugsley');
+    $this->assertRoleCount(0, $account, 'Pugsley has no special roles.');
+
+    // Assert that three roles exist:
+    // - manager;
+    // - editor;
+    // - tester.
+    $roles = $this->roleStorage->loadMultiple();
+    $this->assertEquals(3, count($roles), 'Three roles exist.');
+  }
+
+  /**
+   * Tests mapping to role by role label.
+   */
+  public function testImportByRoleLabels() {
+    // Create the manager and tester roles.
+    $this->createRole([], 'account_manager', 'Account Manager');
+    $this->createRole([], 'software_tester', 'Software Tester');
+
+    // Add mapping to role.
+    $this->feedType->addMapping([
+      'target' => 'roles',
+      'map' => ['target_id' => 'role_labels'],
+      'settings' => [
+        'reference_by' => 'label',
+      ],
+    ]);
+    $this->feedType->save();
+
+    // Import CSV file.
+    $feed = $this->createFeed($this->feedType->id(), [
+      'source' => $this->resourcesPath() . '/csv/users_roles.csv',
+    ]);
+    $feed->import();
+
+    // Assert that Morticia did not get any roles.
+    $account = user_load_by_name('Morticia');
+    $this->assertNotHasRole($account, 'editor', 'Morticia does not have the editor role.');
+    $this->assertRoleCount(0, $account, 'Morticia has no special roles.');
+
+    // Assert that Fester got the manager role and one roles in total.
+    $account = user_load_by_name('Fester');
+    $this->assertHasRole($account, 'account_manager', 'Fester has the manager role.');
+    $this->assertRoleCount(1, $account, 'Fester has one role.');
+
+    // Assert that Gomez got the manager and tester roles.
+    $account = user_load_by_name('Gomez');
+    $this->assertHasRole($account, 'account_manager', 'Gomez has the manager role.');
+    $this->assertHasRole($account, 'software_tester', 'Gomez has the tester role.');
+    $this->assertRoleCount(2, $account, 'Gomez has two roles.');
+
+    // Assert that Pugsley has no roles.
+    $account = user_load_by_name('Pugsley');
+    $this->assertRoleCount(0, $account, 'Pugsley has no special roles.');
+
+    // Assert that two roles exist:
+    // - manager;
+    // - tester.
+    $roles = $this->roleStorage->loadMultiple();
+    $this->assertEquals(2, count($roles), 'Two roles exist.');
+  }
+
+  /**
+   * Tests mapping to role using only allowed roles.
+   */
+  public function testWithAllowedRoles() {
+    // Create the manager and editor roles.
+    $this->createRole([], 'manager');
+    $this->createRole([], 'editor');
+
+    // Add mapping to role. The manager role may not be assigned to the user by
+    // the feed.
+    $this->feedType->addMapping([
+      'target' => 'roles',
+      'map' => ['target_id' => 'role_ids'],
+      'settings' => [
+        'allowed_roles' => [
+          'manager' => FALSE,
+          'editor' => 'editor',
+        ],
+        'autocreate' => TRUE,
+      ],
+    ]);
+    $this->feedType->save();
+
+    // Import CSV file.
+    $feed = $this->createFeed($this->feedType->id(), [
+      'source' => $this->resourcesPath() . '/csv/users_roles.csv',
+    ]);
+    $feed->import();
+
+    // Assert that Morticia got the editor role and one role in total.
+    $account = user_load_by_name('Morticia');
+    $this->assertHasRole($account, 'editor', 'Morticia has the editor role.');
+    $this->assertRoleCount(1, $account, 'Morticia has one role.');
+
+    // Assert that Fester did not got the manager role, because that role was
+    // not an allowed value.
+    $account = user_load_by_name('Fester');
+    $this->assertNotHasRole($account, 'manager', 'Fester does not have the manager role.');
+    $this->assertRoleCount(0, $account, 'Fester has no special roles.');
+
+    // Assert that Gomez only got the tester role and not the manager role.
+    $account = user_load_by_name('Gomez');
+    $this->assertNotHasRole($account, 'manager', 'Gomez does not have the manager role.');
+    $this->assertHasRole($account, 'tester', 'Gomez has the tester role.');
+    $this->assertRoleCount(1, $account, 'Gomez has one role.');
+  }
+
+  /**
+   * Tests that roles can be revoked and that only allowed roles are revoked.
+   */
+  public function testRevokeRoles() {
+    // Create the manager, editor and tester roles.
+    $this->createRole([], 'manager');
+    $this->createRole([], 'editor');
+    $this->createRole([], 'tester');
+
+    // Add mapping to role. The manager role may not be revoked, but the editor
+    // role may.
+    $this->feedType->addMapping([
+      'target' => 'roles',
+      'map' => ['target_id' => 'role_ids'],
+      'settings' => [
+        'allowed_roles' => [
+          'manager' => FALSE,
+          'editor' => 'editor',
+          'tester' => 'tester',
+        ],
+        'revoke_roles' => TRUE,
+      ],
+    ]);
+    $this->feedType->save();
+
+    // Create account for Morticia with roles "manager" and "editor". In the
+    // source only "editor" is specified. Morticia should keep both roles.
+    $this->userStorage->create([
+      'name' => 'Morticia',
+      'mail' => 'morticia@example.com',
+      'pass' => 'mort',
+      'status' => 1,
+      'roles' => [
+        'manager',
+        'editor',
+      ],
+    ])->save();
+    // Create account for Pugsley with roles "manager", "editor" and "tester".
+    // Pugsley has no roles in the source so should only keep the "manager"
+    // role.
+    $this->userStorage->create([
+      'name' => 'Pugsley',
+      'mail' => 'pugsley@example.com',
+      'pass' => 'pugs',
+      'status' => 1,
+      'roles' => [
+        'manager',
+        'editor',
+        'tester',
+      ],
+    ])->save();
+    // Create account for Gomez and give it the "editor" role. Gomez has roles
+    // "tester" and "manager" in the source, so it should lose the "editor" role
+    // and gain the "tester" role.
+    $this->userStorage->create([
+      'name' => 'Gomez',
+      'mail' => 'gomez@example.com',
+      'pass' => 'gome',
+      'status' => 1,
+      'roles' => [
+        'editor',
+      ],
+    ])->save();
+
+    // Import CSV file.
+    $feed = $this->createFeed($this->feedType->id(), [
+      'source' => $this->resourcesPath() . '/csv/users_roles.csv',
+    ]);
+    $feed->import();
+
+    // Assert that Morticia kept the manager and editor roles.
+    $account = user_load_by_name('Morticia');
+    $this->assertHasRole($account, 'manager', 'Morticia still has the manager role.');
+    $this->assertHasRole($account, 'editor', 'Morticia has the editor role.');
+    $this->assertRoleCount(2, $account, 'Morticia has two roles.');
+
+    // Assert that Pugsley only kept the manager role.
+    $account = user_load_by_name('Pugsley');
+    $this->assertHasRole($account, 'manager', 'Pugsley still has the manager role.');
+    $this->assertNotHasRole($account, 'editor', 'Pugsley no longer has the editor role.');
+    $this->assertNotHasRole($account, 'tester', 'Pugsley no longer has the tester role.');
+    $this->assertRoleCount(1, $account, 'Pugsley has one role.');
+
+    // Assert that Gomez lost the editor role, and gained the tester role.
+    $account = user_load_by_name('Gomez');
+    $this->assertNotHasRole($account, 'editor', 'Gomez no longer has the editor role.');
+    $this->assertHasRole($account, 'tester', 'Gomez has the tester role.');
+    $this->assertRoleCount(1, $account, 'Gomez has one role.');
+  }
+
+  /**
+   * Tests if no roles are revoked if the option "Revoke roles" is disabled.
+   */
+  public function testNoRevokeRoles() {
+    // Create the manager and editor roles.
+    $this->createRole([], 'manager');
+    $this->createRole([], 'editor');
+
+    // Add mapping to role. Set option to not revoke roles.
+    $this->feedType->addMapping([
+      'target' => 'roles',
+      'map' => ['target_id' => 'role_ids'],
+      'settings' => [
+        'allowed_roles' => [
+          'manager' => FALSE,
+          'editor' => 'editor',
+        ],
+        'revoke_roles' => FALSE,
+      ],
+    ]);
+    $this->feedType->save();
+
+    // Create account for Pugsley with roles "manager" and "editor". Pugsley has
+    // no roles, but roles should not be revoked, so Pugsley should keep all
+    // roles.
+    $this->userStorage->create([
+      'name' => 'Pugsley',
+      'mail' => 'pugsley@example.com',
+      'pass' => 'pugs',
+      'status' => 1,
+      'roles' => [
+        'manager',
+        'editor',
+      ],
+    ])->save();
+
+    // Import CSV file.
+    $feed = $this->createFeed($this->feedType->id(), [
+      'source' => $this->resourcesPath() . '/csv/users_roles.csv',
+    ]);
+    $feed->import();
+
+    // Assert that Pugsley kept all roles.
+    $account = user_load_by_name('Pugsley');
+    $this->assertHasRole($account, 'manager', 'Pugsley still has the manager role.');
+    $this->assertHasRole($account, 'editor', 'Pugsley still has the editor role.');
+    $this->assertRoleCount(2, $account, 'Pugsley has two roles.');
+  }
+
+}
diff --git a/tests/src/Traits/FeedsCommonTrait.php b/tests/src/Traits/FeedsCommonTrait.php
index c4d428ff..de64c371 100644
--- a/tests/src/Traits/FeedsCommonTrait.php
+++ b/tests/src/Traits/FeedsCommonTrait.php
@@ -204,4 +204,12 @@ trait FeedsCommonTrait {
     }
   }
 
+  /**
+   * Prints messages useful for debugging.
+   */
+  protected function printMessages() {
+    $messages = \Drupal::messenger()->all();
+    print_r($messages);
+  }
+
 }
