diff --git a/core/lib/Drupal/Core/Database/Driver/mysql/Schema.php b/core/lib/Drupal/Core/Database/Driver/mysql/Schema.php
index 878607c55d..38800b48bf 100644
--- a/core/lib/Drupal/Core/Database/Driver/mysql/Schema.php
+++ b/core/lib/Drupal/Core/Database/Driver/mysql/Schema.php
@@ -45,10 +45,10 @@ class Schema extends DatabaseSchema {
   /**
    * Get information about the table and database name from the prefix.
    *
-   * @return
+   * @return array
    *   A keyed array with information about the database, table name and prefix.
    */
-  protected function getPrefixInfo($table = 'default', $add_prefix = TRUE) {
+  public function getPrefixInfo($table = 'default', $add_prefix = TRUE) {
     $info = ['prefix' => $this->connection->tablePrefix($table)];
     if ($add_prefix) {
       $table = $info['prefix'] . $table;
diff --git a/core/lib/Drupal/Core/Database/Driver/pgsql/Connection.php b/core/lib/Drupal/Core/Database/Driver/pgsql/Connection.php
index e696f242fd..b75c1d6562 100644
--- a/core/lib/Drupal/Core/Database/Driver/pgsql/Connection.php
+++ b/core/lib/Drupal/Core/Database/Driver/pgsql/Connection.php
@@ -385,12 +385,11 @@ public function nextId($existing = 0) {
    */
   public function getFullQualifiedTableName($table) {
     $options = $this->getConnectionOptions();
-    $prefix = $this->tablePrefix($table);
+    $info = $this->schema()->getPrefixInfo($table);
 
     // The fully qualified table name in PostgreSQL is in the form of
-    // <database>.<schema>.<table>, so we have to include the 'public' schema in
-    // the return value.
-    return $options['database'] . '.public.' . $prefix . $table;
+    // <database>.<schema>.<table>.
+    return $options['database'] . '.' . $info['schema'] . '.' . $info['table'];
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Database/Driver/pgsql/Schema.php b/core/lib/Drupal/Core/Database/Driver/pgsql/Schema.php
index 9e5e1d9f84..51aec3380a 100644
--- a/core/lib/Drupal/Core/Database/Driver/pgsql/Schema.php
+++ b/core/lib/Drupal/Core/Database/Driver/pgsql/Schema.php
@@ -45,6 +45,15 @@ class Schema extends DatabaseSchema {
    */
   protected $tempNamespaceName;
 
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct($connection) {
+    parent::__construct($connection);
+    $prefix_info = $this->getPrefixInfo();
+    $this->defaultSchema = $prefix_info['schema'];
+  }
+
   /**
    * Make sure to limit identifiers according to PostgreSQL compiled in length.
    *
@@ -54,17 +63,18 @@ class Schema extends DatabaseSchema {
    * tag is one of:
    *   - idx for indexes
    *   - key for constraints
-   *   - pkey for primary keys
+   *   - pkey for primary keys.
    *
-   * @param $identifiers
-   *   The arguments to build the identifier string
-   * @return
-   *   The index/constraint/pkey identifier
+   * @param string $identifiers
+   *   The arguments to build the identifier string.
+   *
+   * @return string
+   *   The index/constraint/pkey quoted identifier.
    */
   protected function ensureIdentifiersLength($identifier) {
     $args = func_get_args();
-    $info = $this->getPrefixInfo($identifier);
-    $args[0] = $info['table'];
+    $prefixInfo = $this->getPrefixInfo($identifier);
+    $args[0] = $prefixInfo['table'];
     $identifierName = implode('__', $args);
 
     // Retrieve the max identifier length which is usually 63 characters
@@ -72,12 +82,13 @@ protected function ensureIdentifiersLength($identifier) {
     $this->maxIdentifierLength = $this->connection->query("SHOW max_identifier_length")->fetchField();
 
     if (strlen($identifierName) > $this->maxIdentifierLength) {
-      $saveIdentifier = '"drupal_' . $this->hashBase64($identifierName) . '_' . $args[2] . '"';
+      $saveIdentifier = 'drupal_' . $this->hashBase64($identifierName) . '_' . $args[2];
     }
     else {
       $saveIdentifier = $identifierName;
     }
-    return $saveIdentifier;
+
+    return $this->connection->escapeTable($saveIdentifier);
   }
 
   /**
@@ -95,16 +106,17 @@ protected function ensureIdentifiersLength($identifier) {
    */
   public function queryTableInformation($table) {
     // Generate a key to reference this table's information on.
-    $key = $this->connection->prefixTables('{' . $table . '}');
+    $prefixInfo = $this->getPrefixInfo($table);
+    $prefixed_table = $prefixInfo['table'];
 
     // Take into account that temporary tables are stored in a different schema.
     // \Drupal\Core\Database\Connection::generateTemporaryTableName() sets the
     // 'db_temporary_' prefix to all temporary tables.
-    if (strpos($key, '.') === FALSE && strpos($table, 'db_temporary_') === FALSE) {
-      $key = 'public.' . $key;
+    if (strpos($prefixed_table, 'db_temporary_') === FALSE) {
+      $key = $prefixInfo['schema'] . '.' . $prefixed_table;
     }
     else {
-      $key = $this->getTempNamespaceName() . '.' . $key;
+      $key = $this->getTempNamespaceName() . '.' . $prefixed_table;
     }
 
     if (!isset($this->tableInformation[$key])) {
@@ -181,14 +193,12 @@ protected function getTempNamespaceName() {
   /**
    * Resets information about table blobs, sequences and serial fields.
    *
-   * @param $table
+   * @param string $table
    *   The non-prefixed name of the table.
    */
   protected function resetTableInformation($table) {
-    $key = $this->connection->prefixTables('{' . $table . '}');
-    if (strpos($key, '.') === FALSE) {
-      $key = 'public.' . $key;
-    }
+    $prefixInfo = $this->getPrefixInfo($table);
+    $key = $prefixInfo['schema'] . '.' . $prefixInfo['table'];
     unset($this->tableInformation[$key]);
   }
 
@@ -424,7 +434,7 @@ public function getFieldTypeMap() {
       'serial:medium' => 'serial',
       'serial:big' => 'bigserial',
       'serial:normal' => 'serial',
-      ];
+    ];
     return $map;
   }
 
@@ -482,36 +492,43 @@ public function renameTable($table, $new_name) {
     }
 
     // Get the schema and tablename for the old table.
-    $old_full_name = $this->connection->prefixTables('{' . $table . '}');
-    list($old_schema, $old_table_name) = strpos($old_full_name, '.') ? explode('.', $old_full_name) : ['public', $old_full_name];
+    $prefixInfo = $this->getPrefixInfo($table);
+    $schema = $prefixInfo['schema'];
+    $table_name = $prefixInfo['table'];
 
     // Index names and constraint names are global in PostgreSQL, so we need to
     // rename them when renaming the table.
-    $indexes = $this->connection->query('SELECT indexname FROM pg_indexes WHERE schemaname = :schema AND tablename = :table', [':schema' => $old_schema, ':table' => $old_table_name]);
+    $indexes = $this->connection->query('SELECT indexname FROM pg_indexes WHERE schemaname = :schema AND tablename = :table', [':schema' => $schema, ':table' => $table_name]);
 
     foreach ($indexes as $index) {
-      // Get the index type by suffix, e.g. idx/key/pkey
-      $index_type = substr($index->indexname, strrpos($index->indexname, '_') + 1);
+      // Append the schema to the index name.
+      $index_short_name = $index->indexname;
+      $index_full_name = $schema . '.' . $index_short_name;
+
+      // Get the index type by suffix, e.g. idx/key/pkey.
+      $index_type = substr($index_short_name, strrpos($index_short_name, '_') + 1);
 
       // If the index is already rewritten by ensureIdentifiersLength() to not
       // exceed the 63 chars limit of PostgreSQL, we need to take care of that.
       // Example (drupal_Gk7Su_T1jcBHVuvSPeP22_I3Ni4GrVEgTYlIYnBJkro_idx).
-      if (strpos($index->indexname, 'drupal_') !== FALSE) {
-        preg_match('/^drupal_(.*)_' . preg_quote($index_type) . '/', $index->indexname, $matches);
+      if (strpos($index_short_name, 'drupal_') !== FALSE) {
+        preg_match('/^drupal_(.*)_' . preg_quote($index_type) . '/', $index_short_name, $matches);
         $index_name = $matches[1];
       }
       else {
         // Make sure to remove the suffix from index names, because
         // $this->ensureIdentifiersLength() will add the suffix again and thus
         // would result in a wrong index name.
-        preg_match('/^' . preg_quote($old_full_name) . '__(.*)__' . preg_quote($index_type) . '/', $index->indexname, $matches);
+        preg_match('/^' . preg_quote($table_name) . '__(.*)__' . preg_quote($index_type) . '/', $index_short_name, $matches);
         $index_name = $matches[1];
       }
-      $this->connection->query('ALTER INDEX "' . $index->indexname . '" RENAME TO ' . $this->ensureIdentifiersLength($new_name, $index_name, $index_type) . '');
+
+      $index_full_name = $this->connection->escapeTable($index_full_name);
+      $this->connection->query('ALTER INDEX ' . $index_full_name . ' RENAME TO ' . $this->ensureIdentifiersLength($new_name, $index_name, $index_type));
     }
 
     // Ensure the new table name does not include schema syntax.
-    $prefixInfo = $this->getPrefixInfo($new_name);
+    $newPrefixInfo = $this->getPrefixInfo($new_name);
 
     // Rename sequences if there's a serial fields.
     $info = $this->queryTableInformation($table);
@@ -523,7 +540,7 @@ public function renameTable($table, $new_name) {
       }
     }
     // Now rename the table.
-    $this->connection->query('ALTER TABLE {' . $table . '} RENAME TO ' . $prefixInfo['table']);
+    $this->connection->query('ALTER TABLE {' . $table . '} RENAME TO ' . $newPrefixInfo['table']);
     $this->resetTableInformation($table);
   }
 
@@ -634,10 +651,17 @@ public function fieldSetNoDefault($table, $field) {
   public function indexExists($table, $name) {
     // Details http://www.postgresql.org/docs/9.1/interactive/view-pg-indexes.html
     $index_name = $this->ensureIdentifiersLength($table, $name, 'idx');
+
     // Remove leading and trailing quotes because the index name is in a WHERE
     // clause and not used as an identifier.
     $index_name = str_replace('"', '', $index_name);
-    return (bool) $this->connection->query("SELECT 1 FROM pg_indexes WHERE indexname = '$index_name'")->fetchField();
+
+    // Get the schema and tablename for the old table.
+    $info = $this->getPrefixInfo($table);
+    $schema = $info['schema'];
+    $table_name = $info['table'];
+
+    return (bool) $this->connection->query("SELECT 1 FROM pg_indexes WHERE schemaname = :schema AND tablename = :table AND indexname = :index", [':schema' => $schema, ':table' => $table_name, ':index' => $index_name])->fetchField();
   }
 
   /**
@@ -750,7 +774,13 @@ public function dropIndex($table, $name) {
       return FALSE;
     }
 
-    $this->connection->query('DROP INDEX ' . $this->ensureIdentifiersLength($table, $name, 'idx'));
+    // Add the schema if not using the default one.
+    $index_name = $this->ensureIdentifiersLength($table, $name, 'idx');
+    // Remove leading and trailing quotes.
+    $index_name = str_replace('"', '', $index_name);
+    $prefix_info = $this->getPrefixInfo($table);
+
+    $this->connection->query('DROP INDEX ' . $this->connection->escapeTable($prefix_info['schema'] . '.' . $index_name));
     $this->resetTableInformation($table);
     return TRUE;
   }
diff --git a/core/lib/Drupal/Core/Database/Schema.php b/core/lib/Drupal/Core/Database/Schema.php
index 80a68f6e5a..e336398523 100644
--- a/core/lib/Drupal/Core/Database/Schema.php
+++ b/core/lib/Drupal/Core/Database/Schema.php
@@ -67,16 +67,16 @@ public function nextPlaceholder() {
   /**
    * Get information about the table name and schema from the prefix.
    *
-   * @param
+   * @param string $table
    *   Name of table to look prefix up for. Defaults to 'default' because that's
    *   default key for prefix.
-   * @param $add_prefix
+   * @param bool $add_prefix
    *   Boolean that indicates whether the given table name should be prefixed.
    *
-   * @return
+   * @return array
    *   A keyed array with information about the schema, table name and prefix.
    */
-  protected function getPrefixInfo($table = 'default', $add_prefix = TRUE) {
+  public function getPrefixInfo($table = 'default', $add_prefix = TRUE) {
     $info = [
       'schema' => $this->defaultSchema,
       'prefix' => $this->connection->tablePrefix($table),
diff --git a/core/modules/migrate/src/Plugin/migrate/id_map/Sql.php b/core/modules/migrate/src/Plugin/migrate/id_map/Sql.php
index 6bdd51ebf0..77ccbf659e 100644
--- a/core/modules/migrate/src/Plugin/migrate/id_map/Sql.php
+++ b/core/modules/migrate/src/Plugin/migrate/id_map/Sql.php
@@ -265,7 +265,23 @@ public function messageTableName() {
    *   The fully qualified map table name.
    */
   public function getQualifiedMapTableName() {
-    return $this->getDatabase()->getFullQualifiedTableName($this->mapTableName);
+    $qualifiedMapTableName = NULL;
+    $connection = $this->getDatabase();
+
+    switch ($connection->databaseType()) {
+      case 'pgsql':
+        // PostgreSQL doesn't support cross DB merges. So only use schema and
+        // prefixed table name.
+        $info = $connection->schema()->getPrefixInfo($this->mapTableName);
+        $qualifiedMapTableName = $info['schema'] . '.' . $info['table'];
+        break;
+
+      default:
+        $qualifiedMapTableName = $connection->getFullQualifiedTableName($this->mapTableName);
+        break;
+    }
+
+    return $qualifiedMapTableName;
   }
 
   /**
diff --git a/core/tests/Drupal/Tests/Core/Database/Driver/pgsql/PostgresqlSchemaTest.php b/core/tests/Drupal/Tests/Core/Database/Driver/pgsql/PostgresqlSchemaTest.php
index d25d2cd281..5524d69f48 100644
--- a/core/tests/Drupal/Tests/Core/Database/Driver/pgsql/PostgresqlSchemaTest.php
+++ b/core/tests/Drupal/Tests/Core/Database/Driver/pgsql/PostgresqlSchemaTest.php
@@ -53,14 +53,21 @@ public function testComputedConstraintName($table_name, $name, $expected) {
 
     $this->connection->expects($this->any())
       ->method('query')
-      ->willReturn($statement);
+      ->will($this->returnValue($statement));
 
-    $this->connection->expects($this->at(2))
-      ->method('query')
-      ->with("SELECT 1 FROM pg_constraint WHERE conname = '$expected'")
-      ->willReturn($this->getMock('\Drupal\Core\Database\StatementInterface'));
+    $this->connection->expects($this->any())
+      ->method('tablePrefix')
+      ->willReturn('');
+
+    $this->connection->expects($this->any())
+      ->method('escapeTable')
+      ->willReturnMap([
+        ['user_field_data____pkey' , '"user_field_data____pkey"'],
+        ['user_field_data__name__key', '"user_field_data__name__key"'],
+        ['a_veeeery_veery_very_super_long_field_name__key', '"drupal_BGGYAXgbqlAF1rMOyFTdZGj9zIMXZtSvEjMAKZ9wGIk_key"'],
+      ]);
 
-    $schema->constraintExists($table_name, $name);
+    $this->assertTrue($schema->constraintExists($table_name, $name));
   }
 
   /**
