diff --git a/src/reader/cif/schema/utils.ts b/src/reader/cif/schema/utils.ts
index 27a5174fa8fcb3a91bf818766867f67545a2ebed..072257addba3f27eae13deb2b03b4042de50684b 100644
--- a/src/reader/cif/schema/utils.ts
+++ b/src/reader/cif/schema/utils.ts
@@ -1,17 +1,16 @@
 
 // import dic from './dic'
-import { Field, FrameSchema } from '../schema'
 import * as Data from '../data-model'
 
-const pooledStr = Field.pooledStr()
-const str = Field.str()
-const int = Field.int()
-const float = Field.float()
-
-export function getFieldType (type: string) {
+export function getFieldType (type: string, values?: string[]) {
     switch (type) {
         case 'code':
         case 'ucode':
+            if (values && values.length) {
+                return `str as Field.Schema<'${values.join("'|'")}'>`
+            } else {
+                return 'str'
+            }
         case 'line':
         case 'uline':
         case 'text':
@@ -47,32 +46,32 @@ export function getFieldType (type: string) {
         case 'boolean':
         case 'symmetry_operation':
         case 'date_dep':
-            return str
+            return 'str'
         case 'uchar3':
         case 'uchar1':
         case 'symop':
-            return pooledStr
+            return 'pooledStr'
         case 'int':
         case 'non_negative_int':
         case 'positive_int':
-            return int
+            return 'int'
         case 'float':
-            return float
+            return 'float'
     }
     console.log(`unknown type '${type}'`)
-    return str
+    return 'str'
 }
 
-type SafeFrameCategories = { [category: string]: Data.Frame }
-type SafeFrameLinks = { [k: string]: string }
+type FrameCategories = { [category: string]: Data.Frame }
+type FrameLinks = { [k: string]: string }
 
-interface SafeFrameData {
-    categories: SafeFrameCategories
-    links: SafeFrameLinks
+interface FrameData {
+    categories: FrameCategories
+    links: FrameLinks
 }
 
 // get field from given or linked category
-function getField ( category: string, field: string, d: Data.Frame, ctx: SafeFrameData): Data.Field|undefined {
+function getField ( category: string, field: string, d: Data.Frame, ctx: FrameData): Data.Field|undefined {
     const { categories, links } = ctx
 
     const cat = d.categories[category]
@@ -87,43 +86,64 @@ function getField ( category: string, field: string, d: Data.Frame, ctx: SafeFra
     }
 }
 
-// function getEnums (d: Data.SafeFrame, ctx: SafeFrameData): string[]|undefined {
-//     const value = getField('_item_enumeration', 'value', d, ctx)
-//     if (value) {
-//         const enums: string[] = []
-//         for (let i = 0; i < value.rowCount; ++i) {
-//             enums.push(value.str(i))
-//             // console.log(value.str(i))
-//         }
-//         return enums
-//     } else {
-//         // console.log(`item_enumeration.value not found for '${d.header}'`)
-//     }
-// }
-
-function getCode (d: Data.Frame, ctx: SafeFrameData): string|undefined {
+function getEnums (d: Data.Frame, ctx: FrameData): string[]|undefined {
+    const value = getField('_item_enumeration', 'value', d, ctx)
+    if (value) {
+        const enums: string[] = []
+        for (let i = 0; i < value.rowCount; ++i) {
+            enums.push(value.str(i))
+            // console.log(value.str(i))
+        }
+        return enums
+    } else {
+        // console.log(`item_enumeration.value not found for '${d.header}'`)
+    }
+}
+
+function getCode (d: Data.Frame, ctx: FrameData): [string, string[]]|undefined {
     const code = getField('_item_type', 'code', d, ctx)
     if (code) {
         let c = code.str(0)
-        // if (c === 'ucode') {
-        //     const enums = getEnums(d, ctx)
-        //     if (enums) c += `: ${enums.join('|')}`
-        // }
-        return c
+        let e = []
+        if (c === 'ucode') {
+            const enums = getEnums(d, ctx)
+            if (enums) e.push(...enums)
+        }
+        return [c, e]
     } else {
         console.log(`item_type.code not found for '${d.header}'`)
     }
 }
 
-export function getSchema (dic: Data.Block) {  // todo Block needs to be specialized with safe frames as well
-    const schema: FrameSchema = {}  // { [category: string]: Category.Schema } = {}
+const header = `/**
+ * Copyright (c) 2017 molio contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Your friendly code generator
+ */
+
+import { Field, TypedFrame } from '../schema'
+
+const pooledStr = Field.pooledStr();
+const str = Field.str();
+const int = Field.int();
+const float = Field.float();`
+
+const footer = `
+type mmCIF = TypedFrame<typeof mmCIF>
+export default mmCIF;`
+
+export function generateSchema (dic: Data.Block) {  // todo Block needs to be specialized with safe frames as well
+    // const schema: FrameSchema = {}  // { [category: string]: Category.Schema } = {}
+    const schema: { [category: string]: { [field: string]: string } } = {}
+
+    const codeLines: string[] = []
 
     // TODO: for fields with finite allowed values, generate:
     // type FieldValue = 'a' | 'b' | 'c'
     // const catetegory = { field: <type> as Field.Schema<FieldValue> }
 
-    const categories: SafeFrameCategories = {}
-    const links: SafeFrameLinks = {}
+    const categories: FrameCategories = {}
+    const links: FrameLinks = {}
     dic.saveFrames.forEach(d => {
         if (d.header[0] !== '_') return
         categories[d.header] = d
@@ -158,11 +178,26 @@ export function getSchema (dic: Data.Block) {  // todo Block needs to be special
 
         const code = getCode(d, { categories, links })
         if (code) {
-            fields[itemName] = getFieldType(code)
+            fields[itemName] = getFieldType(code[0], code[1])
         } else {
             console.log(`could not determine code for '${d.header}'`)
         }
     })
 
-    return schema;
+    schema.entry = { id: 'str' }
+
+    codeLines.push(`const mmCIF = {`)
+    Object.keys(schema).forEach(category => {
+        codeLines.push(`\t${category}: {`)
+        const fields = schema[category]
+        Object.keys(fields).forEach(field => {
+            const type = fields[field]
+            // TODO: check if quoting is required
+            codeLines.push(`\t\t'${field}': ${type},`)
+        })
+        codeLines.push('\t},')
+    })
+    codeLines.push('}')
+
+    return `${header}\n\n${codeLines.join('\n')}\n${footer}`
 }
diff --git a/src/script.ts b/src/script.ts
index fa3b8f3b6a018c1654fa76eb047e1531de0b162a..c10a3e1bd579544c51b1f0a0915e20b76315a95f 100644
--- a/src/script.ts
+++ b/src/script.ts
@@ -10,12 +10,13 @@ import * as fs from 'fs'
 
 require('util.promisify').shim();
 const readFileAsync = util.promisify(fs.readFile);
+const writeFileAsync = util.promisify(fs.writeFile);
 
 import Gro from './reader/gro/parser'
 import CIF from './reader/cif/index'
 
-import { toTypedFrame as applySchema } from './reader/cif/schema'
-import { getSchema } from './reader/cif/schema/utils'
+// import { toTypedFrame as applySchema } from './reader/cif/schema'
+import { generateSchema } from './reader/cif/schema/utils'
 
 const file = '1crn.gro'
 // const file = 'water.gro'
@@ -109,16 +110,16 @@ async function runCIF(input: string | Uint8Array) {
     console.log(mmcif.entity.type.toArray());
     console.log(mmcif.pdbx_struct_oper_list.matrix.value(0));
 
-    const schema = await _dic()
-    if (schema) {
-        const mmcif2 = applySchema(schema, data)
-        // console.log(util.inspect(mmcif2.atom_site, {showHidden: false, depth: 3}))
-        console.log(mmcif2.atom_site.Cartn_x.value(0));
-        console.log(mmcif2.entity.type.toArray());
-        // console.log(mmcif2.pdbx_struct_oper_list.matrix.value(0)); // TODO
-    } else {
-        console.log('error getting mmcif schema from dic')
-    }
+    // const schema = await _dic()
+    // if (schema) {
+    //     const mmcif2 = applySchema(schema, data)
+    //     // console.log(util.inspect(mmcif2.atom_site, {showHidden: false, depth: 3}))
+    //     console.log(mmcif2.atom_site.Cartn_x.value(0));
+    //     console.log(mmcif2.entity.type.toArray());
+    //     // console.log(mmcif2.pdbx_struct_oper_list.matrix.value(0)); // TODO
+    // } else {
+    //     console.log('error getting mmcif schema from dic')
+    // }
 }
 
 export async function _cif() {
@@ -153,10 +154,12 @@ async function runDic(input: string | Uint8Array) {
         return;
     }
 
-    const schema = getSchema(parsed.result.blocks[0])
-    console.log(util.inspect(schema, {showHidden: false, depth: 3}))
+    const schema = generateSchema(parsed.result.blocks[0])
+    // console.log(schema)
     // console.log(util.inspect(Object.keys(schema).length, {showHidden: false, depth: 1}))
 
+    await writeFileAsync('./src/reader/cif/schema/mmcif-gen.ts', schema, 'utf8')
+
     return schema
 }
 
@@ -168,7 +171,7 @@ export async function _dic() {
     return runDic(input);
 }
 
-// _dic();
+_dic();
 
 import Computation from './utils/computation'
 const comp = Computation.create(async ctx => {