diff --git a/src/mol-data/db.ts b/src/mol-data/db.ts
index 8ae56bde7ce1d70114798034674f09564327cb54..e783dac4f7eb88954cd4955805efcbf1047b113a 100644
--- a/src/mol-data/db.ts
+++ b/src/mol-data/db.ts
@@ -10,6 +10,6 @@ import Table from './db/table'
 import Column from './db/column'
 import * as ColumnHelpers from './db/column-helpers'
 
-type DatabaseCollection = { [name: string]: Database<Database.Schema> }
+type DatabaseCollection<T extends Database.Schema> = { [name: string]: Database<T> }
 
 export { DatabaseCollection, Database, Table, Column, ColumnHelpers }
\ No newline at end of file
diff --git a/src/mol-data/db/column.ts b/src/mol-data/db/column.ts
index af668d4f58bf260858546ef29fffd80e4965e421..163cdcb3eba219b97d57e59e80e061f54f612850 100644
--- a/src/mol-data/db/column.ts
+++ b/src/mol-data/db/column.ts
@@ -150,6 +150,19 @@ namespace Column {
         if (!c.isDefined) return Undefined(c.rowCount, c.schema) as any as Column<T>;
         return arrayColumn({ array: c.toArray({ array }), schema: c.schema, valueKind: c.valueKind });
     }
+
+    export function copyToArray<T>(c: Column<T>, array: ArrayLike<T>, offset = 0) {
+        if (!c.isDefined) return;
+        const cArray = c['@array']
+        if (cArray) {
+            // TODO Index signature of 'ArrayLike<T>' only permits reading
+            for (let i = 0, _i = cArray.length; i < _i; i++) (array[offset + i] as any) = cArray[i];
+        } else {
+            // TODO Index signature of 'ArrayLike<T>' only permits reading
+            for (let i = 0, _i = c.rowCount; i < _i; i++) (array[offset + i] as any) = c.value(i);
+        }
+
+    }
 }
 
 export default Column;
diff --git a/src/mol-data/db/table.ts b/src/mol-data/db/table.ts
index 222d71d2e94642469c4183dd2273b42768650004..cac162233387ca44e924942752b1b54c7b7298fc 100644
--- a/src/mol-data/db/table.ts
+++ b/src/mol-data/db/table.ts
@@ -100,6 +100,32 @@ namespace Table {
         return ret as Table<R>;
     }
 
+    export function concat<S extends R, R extends Schema>(tables: Table<S>[], schema: R) {
+        const ret = Object.create(null);
+        const columns = Object.keys(schema);
+        ret._rowCount = 0
+        for (const table of tables) {
+            ret._rowCount += table._rowCount
+        }
+        const arrays: any = {}
+        for (const column of columns) {
+            arrays[column] = new Array(ret._rowCount)
+        }
+        ret._columns = columns;
+        ret._schema = schema;
+        let offset = 0
+        for (const table of tables) {
+            for (const k of columns) {
+                Column.copyToArray(table[k], arrays[k], offset)
+            }
+            offset += table._rowCount
+        }
+        for (const k of columns) {
+            ret[k] = Column.ofArray({ array: arrays[k], schema: schema[k] })
+        }
+        return ret as Table<R>;
+    }
+
     export function columnToArray<S extends Schema>(table: Table<S>, name: keyof S, array?: Column.ArrayCtor<any>) {
         (table as Columns<S>)[name] = Column.asArrayColumn((table as Columns<S>)[name], array);
     }
diff --git a/src/mol-io/writer/cif.ts b/src/mol-io/writer/cif.ts
index 36c5128fde3c207b6094f5c252c5cb5db10d7e2f..10438f5d670af277a46f8abcf7e4fec6fbf61acb 100644
--- a/src/mol-io/writer/cif.ts
+++ b/src/mol-io/writer/cif.ts
@@ -29,7 +29,7 @@ export function writeDatabase(encoder: CIFEncoder, name: string, database: Datab
     }
 }
 
-export function writeDatabaseCollection(encoder: CIFEncoder, collection: DatabaseCollection) {
+export function writeDatabaseCollection(encoder: CIFEncoder, collection: DatabaseCollection<Database.Schema>) {
     for (const name of Object.keys(collection)) {
         writeDatabase(encoder, name, collection[name])
     }