diff --git a/src/mol-data/structure/export/mmcif.ts b/src/mol-data/structure/export/mmcif.ts
index d3fb005b040bf5fcf146b59f468b284dadc8f95d..2d4a2443cfde1df0aba6e5fc8e6efaad3e35f3ef 100644
--- a/src/mol-data/structure/export/mmcif.ts
+++ b/src/mol-data/structure/export/mmcif.ts
@@ -4,10 +4,10 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import { Column } from 'mol-base/collections/database'
+import { Column, Table } from 'mol-base/collections/database'
 import Iterator from 'mol-base/collections/iterator'
 import * as Encoder from 'mol-io/writer/cif/encoder'
-import { mmCIF_Database } from 'mol-io/reader/cif/schema/mmcif'
+import { mmCIF_Schema } from 'mol-io/reader/cif/schema/mmcif'
 import CIFEncoder from 'mol-io/writer/cif/encoder/text'
 import { Structure, Atom, AtomSet } from '../structure'
 import { Model } from '../model'
@@ -18,36 +18,75 @@ interface Context {
     model: Model
 }
 
-function str<K, D = any>(name: string, value: (k: K, d: D) => string, valueKind?: (k: K) => Column.ValueKind): Encoder.FieldDefinition<K, any> {
+function str<K, D>(name: string, value: (k: K, d: D) => string, valueKind?: (k: K) => Column.ValueKind): Encoder.FieldDefinition<K, D> {
     return { name, type: Encoder.FieldType.Str, value, valueKind }
 }
 
-function int<K, D = any>(name: string, value: (k: K, d: D) => number, valueKind?: (k: K) => Column.ValueKind): Encoder.FieldDefinition<K, any> {
+function int<K, D = any>(name: string, value: (k: K, d: D) => number, valueKind?: (k: K) => Column.ValueKind): Encoder.FieldDefinition<K, D> {
     return { name, type: Encoder.FieldType.Int, value, valueKind }
 }
 
-function float<K, D = any>(name: string, value: (k: K, d: D) => number, valueKind?: (k: K) => Column.ValueKind): Encoder.FieldDefinition<K, any> {
+function float<K, D = any>(name: string, value: (k: K, d: D) => number, valueKind?: (k: K) => Column.ValueKind): Encoder.FieldDefinition<K, D> {
     return { name, type: Encoder.FieldType.Float, value, valueKind }
 }
 
-type Entity =  mmCIF_Database['entity'];
+// function col<K, D>(name: string, c: (data: D) => Column<any>): Encoder.FieldDefinition<K, D> {
+//     const kind = c['@type'].kind;
+//     // TODO: matrix/vector/support
+//     const type = kind === 'str' ? Encoder.FieldType.Str : kind === 'int' ? Encoder.FieldType.Int : Encoder.FieldType.Float
+//     return { name, type, value, valueKind }
+// }
+
+function columnValue(k: string) {
+    return (i: number, d: any) => d[k].value(i);
+}
+
+function columnValueKind(k: string) {
+    return (i: number, d: any) => d[k].valueKind(i);
+}
+
+function ofSchema(schema: Table.Schema) {
+    const fields: Encoder.FieldDefinition[] = [];
+    for (const k of Object.keys(schema)) {
+        const t = schema[k];
+        // TODO: matrix/vector/support
+        const type = t.kind === 'str' ? Encoder.FieldType.Str : t.kind === 'int' ? Encoder.FieldType.Int : Encoder.FieldType.Float;
+        fields.push({ name: k, type, value: columnValue(k), valueKind: columnValueKind(k) })
+    }
+    return fields;
+}
+
+type Entity = Table.Columns<typeof mmCIF_Schema.entity>
 
 const entity: Encoder.CategoryDefinition<number, Entity> = {
     name: 'entity',
-    fields: [
-        str<number, Entity>('id', (i, e) => e.id.value(i)),
-        str<number, Entity>('type', (i, e) => e.type.value(i)),
-        str<number, Entity>('src_method', (i, e) => e.src_method.value(i)),
-        str<number, Entity>('pdbx_description', (i, e) => e.pdbx_description.value(i)),
-        int<number, Entity>('formula_weight', (i, e) => e.formula_weight.value(i)),
-        float<number, Entity>('pdbx_number_of_molecules', (i, e) => e.pdbx_number_of_molecules.value(i)),
-        str<number, Entity>('details', (i, e) => e.details.value(i)),
-        str<number, Entity>('pdbx_mutation', (i, e) => e.pdbx_mutation.value(i)),
-        str<number, Entity>('pdbx_fragment', (i, e) => e.pdbx_fragment.value(i)),
-        str<number, Entity>('pdbx_ec', (i, e) => e.pdbx_ec.value(i)),
-    ]
+    fields: ofSchema(mmCIF_Schema.entity)
 }
 
+// [
+//     str('id', (i, e) => e.id.value(i)),
+//     str('type', (i, e) => e.type.value(i)),
+//     str('src_method', (i, e) => e.src_method.value(i)),
+//     str('pdbx_description', (i, e) => e.pdbx_description.value(i)),
+//     int('formula_weight', (i, e) => e.formula_weight.value(i)),
+//     float('pdbx_number_of_molecules', (i, e) => e.pdbx_number_of_molecules.value(i)),
+//     str('details', (i, e) => e.details.value(i)),
+//     str('pdbx_mutation', (i, e) => e.pdbx_mutation.value(i)),
+//     str('pdbx_fragment', (i, e) => e.pdbx_fragment.value(i)),
+//     str('pdbx_ec', (i, e) => e.pdbx_ec.value(i)),
+// ]
+
+// type AtomSite = typeof mmCIF_Schema.atom_site;
+// type DataSource<Key, Schema extends Table.Schema> = { [P in keyof Schema]: (key: Key) => Schema[P]['T'] }
+
+// export const atom_site1: Partial<DataSource<Atom.Location, AtomSite>> = {
+//     group_PDB: P.residue.group_PDB,
+//     id: P.atom.id,
+//     type_symbol: P.atom.type_symbol as any,
+//     label_atom_id: P.atom.label_atom_id,
+//     //...
+// }
+
 const atom_site: Encoder.CategoryDefinition<Atom.Location> = {
     name: 'atom_site',
     fields: [
diff --git a/src/mol-io/writer/cif/encoder/text.ts b/src/mol-io/writer/cif/encoder/text.ts
index 06c1d67d29f718b74c6f354e7d33fc6ee279a315..46b3fd4cdf599718e302f461442a5e75fecd19d2 100644
--- a/src/mol-io/writer/cif/encoder/text.ts
+++ b/src/mol-io/writer/cif/encoder/text.ts
@@ -60,7 +60,7 @@ export default class TextCIFEncoder<Context> implements Enc.CIFEncoder<string, C
     }
 }
 
-function writeValue(builder: StringBuilder, data: any, key: any, f: Enc.FieldDefinition): boolean {
+function writeValue(builder: StringBuilder, data: any, key: any, f: Enc.FieldDefinition<any, any>): boolean {
     const kind = f.valueKind;
     const p = kind ? kind(key, data) : Column.ValueKind.Present;
     if (p !== Column.ValueKind.Present) {