diff --git a/core/lib/Drupal/Core/Database/Driver/mysql/Merge.php b/core/lib/Drupal/Core/Database/Driver/mysql/Merge.php
index c48b830..991aec7 100644
--- a/core/lib/Drupal/Core/Database/Driver/mysql/Merge.php
+++ b/core/lib/Drupal/Core/Database/Driver/mysql/Merge.php
@@ -8,5 +8,327 @@
 namespace Drupal\Core\Database\Driver\mysql;
 
 use Drupal\Core\Database\Query\Merge as QueryMerge;
+use Drupal\Core\Database\Query\SelectInterface;
+use Drupal\Core\Database\Query\PlaceholderInterface;
+use Drupal\Core\Database\Query\InvalidMergeQueryException;
+use Drupal\Core\Database\Connection as DBConnection;
+use Drupal\Core\Database\Database;
+use Drupal\Core\Database\IntegrityConstraintViolationException;
 
-class Merge extends QueryMerge { }
+
+class Merge extends \Drupal\Core\Database\Query\Query implements \Drupal\Core\Database\Query\ConditionInterface {
+
+  /**
+   * Tablename
+   *
+   * @var string
+   */
+  protected $table;
+
+  /**
+   * Array of table columns excluding serial that need to be met by
+   * insertFields before a REPLACE can be considered
+   *
+   * @var array
+   */
+  protected $tableColumns;
+
+  /**
+   * Flag indicating whether an REPLACE is possible.
+   *
+   * @var boolean
+   */
+  protected $mergeOnUnique = TRUE;
+
+  /**
+   * QueryMerge object that does the merge if a REPLACE cannot be done.
+   *
+   * @var Drupal\Core\Database\Query\Merge
+   */
+  protected $queryMerge;
+
+  /**
+   * The unique and primary keys of the table
+   *
+   * @var array
+   */
+  protected $uniqueKeys;
+
+  /**
+   * The array from the key/keys call
+   *
+   * @var array
+   */
+  protected $keysStored = array();
+
+  public function __construct(Connection $connection, $table, array $options = array()) {
+    parent::__construct($connection, $options);
+    $this->queryMerge = new QueryMerge($connection, $table, $options);
+    $this->table = $table;
+    $schema = drupal_get_schema($table);
+    if ($schema) {
+      if (isset($schema['primary key'])) {
+        $uniquekeys = $schema['primary key'];
+      }
+      else {
+        $uniquekeys = array();
+      }
+      if (isset($schema['unique keys'])) {
+        $uniquekeys = array_merge($uniquekeys, $schema['unique keys']);
+      }
+      if (empty($uniquekeys)) {
+        $this->mergeOnUnique = FALSE;
+      }
+      else {
+        $this->uniqueKeys = array_values($uniquekeys);
+
+        // get a column list
+        $fields = $schema['fields'];
+        foreach ($fields as $column => $attributes) {
+          if ($attributes['type'] == 'serial') { 
+            unset($fields[$column]);
+            break;
+          }
+        }
+        $this->tableColumns = $fields;
+      }
+    }
+    else {
+      $this->mergeOnUnique = FALSE;
+    }
+  }
+
+  public function updateFields(array $fields) {
+    $this->queryMerge->updateFields($fields);
+    return $this;
+  }
+
+  public function expression($field, $expression, array $arguments = NULL) {
+    $this->mergeOnUnique = FALSE;
+    return $this->queryMerge->expression($field, $expression, $arguments);
+  }
+
+  public function insertFields(array $fields, array $values = array()) {
+    $this->queryMerge->insertFields($fields, $values);
+    return $this;
+  }
+
+  public function useDefaults(array $fields) {
+    $this->queryMerge->useDefaults($fields);
+    return $this;
+  }
+
+  public function fields(array $fields, array $values = array()) {
+    $this->queryMerge->fields($fields, $values);
+    return $this;
+  }
+
+  /**
+   * Sets the key field to be used as conditions for this query.
+   *
+   * @return $this
+   */
+  public function key($field, $value = NULL) {
+    if ($this->mergeOnUnique and array_search($field, $this->uniqueKeys)) {
+      $this->mergeOnUnique = FALSE;
+      return $this->queryMerge->key($field, $value);
+    }
+    // @todo D9: Remove this backwards-compatibility shim.
+    if (is_array($field)) {
+      $this->keysStored = isset($value) ? array_combine($field, $value) : $field;
+    }
+    else {
+      $this->keysStored = array($field => $value);
+    }
+    $this->queryMerge->key($field, $value);
+    return $this;
+  }
+
+  /**
+   * Sets the key fields to be used as conditions for this query.
+   *
+   * @return $this
+   */
+  public function keys(array $fields, array $values = array()) {
+    if ($this->mergeOnUnique) {
+      foreach ($this->uniqueKeys as $uq) {
+        $diff = array_diff($uq, $fields);
+        if (!empty($diff)) {
+          $this->mergeOnUnique = FALSE;
+          return $this->queryMerge->keys($fields, $values);
+        }
+      }
+    }
+    if ($values) {
+      $this->keysStored = array_combine($fields, $values);
+    } else {
+      $this->keysStored = $fields;
+    }
+    $this->queryMerge->keys($fields, $values);
+    return $this;
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::condition().
+   */
+  public function condition($field, $value = NULL, $operator = NULL) {
+    $this->mergeOnUnique = FALSE;
+    return $this->queryMerge->condition($field, $value, $operator);
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::where().
+   */
+  public function where($snippet, $args = array()) {
+    $this->mergeOnUnique = FALSE;
+    return $this->queryMerge->where($snippet, $args);
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::isNull().
+   */
+  public function isNull($field) {
+    $this->mergeOnUnique = FALSE;
+    return $this->queryMerge->isNull($field);
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::isNotNull().
+   */
+  public function isNotNull($field) {
+    $this->mergeOnUnique = FALSE;
+    return $this->queryMerge->isNotNull($field);
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::exists().
+   */
+  public function exists(SelectInterface $select) {
+    $this->mergeOnUnique = FALSE;
+    return $this->queryMerge->exists($select);
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::notExists().
+   */
+  public function notExists(SelectInterface $select) {
+    $this->mergeOnUnique = FALSE;
+    return $this->queryMerge->notExists($select);
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::conditions().
+   */
+  public function &conditions()  {
+    return $this->queryMerge->conditions();
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::arguements().
+   */
+  public function arguments() {
+    return $this->queryMerge->arguements();
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::compile().
+   */
+  public function compile(DBConnection $connection, PlaceholderInterface $queryPlaceholder) {
+    return $this->queryMerge->compile($connection, $queryPlaceholder);
+  }
+
+  /**
+   * Implements Drupal\Core\Database\Query\ConditionInterface::compiled().
+   */
+  public function compiled() {
+    return $this->queryMerge->compiled();
+  }
+
+  public function execute() {
+    if ($this->mergeOnUnique) {
+
+      $this->queryOptions += array(
+        'throw_exception' => TRUE,
+      );
+
+      if (empty($this->keysStored) and $this->queryOptions['throw_exception']) {
+        throw new InvalidMergeQueryException(t('Invalid merge query: no conditions'));
+      }
+      // remerge in keysStored
+      $insertFieldValues = array_merge($this->keysStored, $this->queryMerge->getInsertFields()); 
+      $updateFieldValues = $this->queryMerge->getUpdateFields(); 
+      $defaultFieldValues = $this->queryMerge->getDefaults(); 
+
+
+      // check if there is less insert fields than update fields
+      $insertLessUpdate = array_diff(array_keys($insertFieldValues), array_keys($updateFieldValues), $this->uniqueKeys);
+
+      // merge is an insert or update. If it doesn't contain all fields in insert then REPLACE isn't appropriate
+      $unfilledcolumns = array_diff_key($this->tableColumns, $insertFieldValues);
+
+      if (empty($insertLessUpdate) and empty($unfilledcolumns)) {
+        // keys == insert - update  therefore replace
+        $replace = TRUE;
+        $query = 'REPLACE ';
+      }
+      else {
+        $replace = FALSE;
+        $query = 'INSERT ';
+      }
+
+      $fields = array_keys($insertFieldValues) + array_keys($defaultFieldValues);
+      $query = $query . ' INTO {' . $this->table . '} ( ' . join(',  ', $fields) . ') VALUES ';
+
+      // Overwrite default values with real values
+      $v = array_merge($defaultFieldValues, $insertFieldValues);
+
+      $placeArray = array_map('self::toSQLPlace', array_keys($v));
+      $values = array_combine($placeArray, array_values($v));
+      $query = $query . '( ' . join(', ', $placeArray) . ' )';
+      if (!$replace) {
+
+        $v = array_merge($defaultFieldValues, $updateFieldValues);
+
+        // With an empty update values we just leave it as an insert
+        // and catch and ignore the duplicate key error.
+        if (!empty($v)) {
+          // on INSERT ON DUPLICATE KEY UPDATE
+          $query = $query . ' ON DUPLICATE KEY UPDATE ';
+
+          $placeArray = array_map('self::toSQLPlace', array_keys($v), array('__update'));
+
+          $values = $values + array_combine($placeArray, array_values($v));
+          foreach (array_combine(array_keys($v), $placeArray) as $k => $value) {
+            $query = $query . $k . ' = ' . $value . ', ';
+          }
+          $query = substr($query, 0, -2);
+        }
+      }
+
+      try {
+        $affected = $this->queryMerge->getConnection()->query($query, $values, array('return' => Database::RETURN_AFFECTED));
+      }
+      catch (IntegrityConstraintViolationException $e) {
+        // just ignore this error as its an INSERT without an ON DUPLICATE KEY UPDATE
+        return QueryMerge::STATUS_UPDATE;
+      }
+      if ($affected > 1) {
+        return QueryMerge::STATUS_UPDATE;
+      }
+      else {
+        return QueryMerge::STATUS_INSERT;
+      }
+    }
+    else {
+      return $this->queryMerge->execute();
+    }
+  }
+
+  public function __toString() {
+  }
+
+  protected static function toSQLPlace($in, $extra = '') {
+    return ':' . $in . $extra;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Database/Query/Merge.php b/core/lib/Drupal/Core/Database/Query/Merge.php
index d1b52e6..d3bc680 100644
--- a/core/lib/Drupal/Core/Database/Query/Merge.php
+++ b/core/lib/Drupal/Core/Database/Query/Merge.php
@@ -249,6 +249,32 @@ public function useDefaults(array $fields) {
   }
 
   /**
+   * Returns fields/values passed to the useDefaults.
+   *
+   * @return array
+   */
+  public function getDefaults() {
+    return $this->defaultFields;
+  }
+
+  /**
+   * Returns fields/values for inserting.
+   *
+   * @return array
+   */
+  public function getInsertFields() {
+    return $this->insertFields;
+  }
+
+  /**
+   * Returns fields for updating.
+   *
+   * @return array
+   */
+  public function getUpdateFields() {
+    return $this->updateFields;
+  }
+  /**
    * Sets common field-value pairs in the INSERT and UPDATE query parts.
    *
    * This method should only be called once. It may be called either
diff --git a/core/lib/Drupal/Core/Database/Query/Query.php b/core/lib/Drupal/Core/Database/Query/Query.php
index 790ed5c..51a2040 100644
--- a/core/lib/Drupal/Core/Database/Query/Query.php
+++ b/core/lib/Drupal/Core/Database/Query/Query.php
@@ -181,6 +181,15 @@ public function &getComments() {
   }
 
   /**
+   * Returns a connection object associated with the Query
+   *
+   * @return \Drupal\Core\Database\Connection
+   */
+  public function getConnection() {
+    return $this->connection;
+  }
+
+  /**
    * {@inheritdoc}
    */
   public function conditionGroupFactory($conjunction = 'AND') {
