diff --git a/src/mol-model/structure/model/formats/mmcif.ts b/src/mol-model/structure/model/formats/mmcif.ts
index 155a94777881da609608b77cea9d6a0620d21446..31c4dfc1e41bffce4526dd59ee2302d9bde12fb2 100644
--- a/src/mol-model/structure/model/formats/mmcif.ts
+++ b/src/mol-model/structure/model/formats/mmcif.ts
@@ -88,24 +88,6 @@ function getModifiedResidueNameMap(format: mmCIF_Format): Model['properties']['m
     return { parentId, details };
 }
 
-function getAsymIdSerialMap(format: mmCIF_Format): ReadonlyMap<string, number> {
-    const data = format.data.struct_asym;
-    const map = new Map<string, number>();
-    let serial = 0
-
-    const id = data.id
-    const count = data._rowCount
-    for (let i = 0; i < count; ++i) {
-        const _id = id.value(i)
-        if (!map.has(_id)) {
-            map.set(_id, serial)
-            serial += 1
-        }
-    }
-
-    return map;
-}
-
 function getChemicalComponentMap(format: mmCIF_Format): ChemicalComponentMap {
     const map = new Map<string, ChemicalComponent>();
     const { id, type, name, pdbx_synonyms, formula, formula_weight } = format.data.chem_comp
@@ -150,7 +132,6 @@ function getSaccharideComponentMap(format: mmCIF_Format): SaccharideComponentMap
 
 export interface FormatData {
     modifiedResidues: Model['properties']['modifiedResidues']
-    asymIdSerialMap: Model['properties']['asymIdSerialMap']
     chemicalComponentMap: Model['properties']['chemicalComponentMap']
     saccharideComponentMap: Model['properties']['saccharideComponentMap']
 }
@@ -158,7 +139,6 @@ export interface FormatData {
 function getFormatData(format: mmCIF_Format): FormatData {
     return {
         modifiedResidues: getModifiedResidueNameMap(format),
-        asymIdSerialMap: getAsymIdSerialMap(format),
         chemicalComponentMap: getChemicalComponentMap(format),
         saccharideComponentMap: getSaccharideComponentMap(format)
     }
diff --git a/src/mol-model/structure/model/model.ts b/src/mol-model/structure/model/model.ts
index 1eaad6e4554730175c54c80fb651b27cb71ac2e3..a9442fc948c6ffe8e1de0f19236ec750760e8a68 100644
--- a/src/mol-model/structure/model/model.ts
+++ b/src/mol-model/structure/model/model.ts
@@ -47,8 +47,6 @@ export interface Model extends Readonly<{
             parentId: ReadonlyMap<string, string>,
             details: ReadonlyMap<string, string>
         }>,
-        /** maps asym id to unique serial number */
-        readonly asymIdSerialMap: ReadonlyMap<string, number>
         /** maps residue name to `ChemicalComponent` data */
         readonly chemicalComponentMap: ChemicalComponentMap
         /** maps residue name to `SaccharideComponent` data */
diff --git a/src/mol-repr/structure/representation/cartoon.ts b/src/mol-repr/structure/representation/cartoon.ts
index ccb54f9332aca73d05b0e589cc31cbe7352a5028..4d21933e882b5a8274eabd8eee013a36c9d51f58 100644
--- a/src/mol-repr/structure/representation/cartoon.ts
+++ b/src/mol-repr/structure/representation/cartoon.ts
@@ -31,7 +31,7 @@ export const CartoonParams = {
     ...NucleotideBlockParams,
     ...PolymerDirectionParams,
     sizeFactor: PD.Numeric(0.2, { min: 0, max: 10, step: 0.01 }),
-    colorTheme: PD.Mapped('polymer-index', BuiltInColorThemeOptions, getBuiltInColorThemeParams),
+    colorTheme: PD.Mapped('polymer-id', BuiltInColorThemeOptions, getBuiltInColorThemeParams),
     visuals: PD.MultiSelect<CartoonVisualName>(['polymer-trace', 'polymer-gap', 'nucleotide-block'], CartoonVisualOptions),
 }
 PD.getDefaultValues(CartoonParams).colorTheme.name
diff --git a/src/mol-repr/structure/representation/molecular-surface.ts b/src/mol-repr/structure/representation/molecular-surface.ts
index cdf89b914e547ee033b46552881bc8d4383440ca..71ac6eb26fa22999ce6aaa6b7dfde09dd76927fb 100644
--- a/src/mol-repr/structure/representation/molecular-surface.ts
+++ b/src/mol-repr/structure/representation/molecular-surface.ts
@@ -27,7 +27,7 @@ export const MolecularSurfaceParams = {
     ...GaussianSurfaceParams,
     ...GaussianWireframeParams,
     ...GaussianDensityVolumeParams,
-    colorTheme: PD.Mapped('polymer-index', BuiltInColorThemeOptions, getBuiltInColorThemeParams),
+    colorTheme: PD.Mapped('polymer-id', BuiltInColorThemeOptions, getBuiltInColorThemeParams),
     visuals: PD.MultiSelect<MolecularSurfaceVisualName>(['gaussian-surface'], MolecularSurfaceVisualOptions),
 }
 PD.getDefaultValues(MolecularSurfaceParams).colorTheme.name
diff --git a/src/mol-theme/color.ts b/src/mol-theme/color.ts
index 31c5b3fd542397ba368eb6e7ed53c751621b69b3..52d9608cf8e9269fd24926dabda99bea3eadb597 100644
--- a/src/mol-theme/color.ts
+++ b/src/mol-theme/color.ts
@@ -17,6 +17,7 @@ import { CrossLinkColorThemeProvider } from './color/cross-link';
 import { ElementIndexColorThemeProvider } from './color/element-index';
 import { ElementSymbolColorThemeProvider } from './color/element-symbol';
 import { MoleculeTypeColorThemeProvider } from './color/molecule-type';
+import { PolymerIdColorThemeProvider } from './color/polymer-id';
 import { PolymerIndexColorThemeProvider } from './color/polymer-index';
 import { ResidueNameColorThemeProvider } from './color/residue-name';
 import { SecondaryStructureColorThemeProvider } from './color/secondary-structure';
@@ -96,6 +97,7 @@ export const BuiltInColorThemes = {
     'element-index': ElementIndexColorThemeProvider,
     'element-symbol': ElementSymbolColorThemeProvider,
     'molecule-type': MoleculeTypeColorThemeProvider,
+    'polymer-id': PolymerIdColorThemeProvider,
     'polymer-index': PolymerIndexColorThemeProvider,
     'residue-name': ResidueNameColorThemeProvider,
     'secondary-structure': SecondaryStructureColorThemeProvider,
diff --git a/src/mol-theme/color/chain-id.ts b/src/mol-theme/color/chain-id.ts
index 2983ce357fef282afe23182257b8e558fc8cb59f..0d90464d8fafe845e6db32af937870f0fa44d3cc 100644
--- a/src/mol-theme/color/chain-id.ts
+++ b/src/mol-theme/color/chain-id.ts
@@ -12,6 +12,7 @@ import { ColorTheme, LocationColor } from '../color';
 import { ParamDefinition as PD } from 'mol-util/param-definition'
 import { ThemeDataContext } from 'mol-theme/theme';
 import { ColorListOptions, ColorListName } from 'mol-util/color/scale';
+import { Column } from 'mol-data/db';
 
 const DefaultColor = Color(0xCCCCCC)
 const Description = 'Gives every chain a color based on its `asym_id` value.'
@@ -34,6 +35,17 @@ function getAsymId(unit: Unit): StructureElement.Property<string> {
     }
 }
 
+function addAsymIds(map: Map<string, number>, data: Column<string>) {
+    let j = map.size
+    for (let o = 0, ol = data.rowCount; o < ol; ++o) {
+        const k = data.value(o)
+        if (!map.has(k)) {
+            map.set(k, j)
+            j += 1
+        }
+    }
+}
+
 export function ChainIdColorTheme(ctx: ThemeDataContext, props: ChainIdColorThemeProps): ColorTheme<ChainIdColorThemeProps> {
     let color: LocationColor
     const scale = ColorScale.create({ listOrName: props.list, minLabel: 'Start', maxLabel: 'End' })
@@ -42,14 +54,13 @@ export function ChainIdColorTheme(ctx: ThemeDataContext, props: ChainIdColorThem
         const l = StructureElement.create()
         const { models } = ctx.structure
         const asymIdSerialMap = new Map<string, number>()
-        let j = 0
         for (let i = 0, il = models.length; i <il; ++i) {
-            models[i].properties.asymIdSerialMap.forEach((v, k) => {
-                if (!asymIdSerialMap.has(k)) {
-                    asymIdSerialMap.set(k, j)
-                    j += 1
-                }
-            })
+            const m = models[i]
+            addAsymIds(asymIdSerialMap, m.atomicHierarchy.chains.label_asym_id)
+            if (m.coarseHierarchy.isDefined) {
+                addAsymIds(asymIdSerialMap, m.coarseHierarchy.spheres.asym_id)
+                addAsymIds(asymIdSerialMap, m.coarseHierarchy.gaussians.asym_id)
+            }
         }
         scale.setDomain(0, asymIdSerialMap.size - 1)
         const scaleColor = scale.color
diff --git a/src/mol-theme/color/polymer-id.ts b/src/mol-theme/color/polymer-id.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c543ca7e09eaeaed62e1411dd44577e3302a68bc
--- /dev/null
+++ b/src/mol-theme/color/polymer-id.ts
@@ -0,0 +1,104 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { Unit, StructureProperties, StructureElement, Link } from 'mol-model/structure';
+
+import { ColorScale, Color } from 'mol-util/color';
+import { Location } from 'mol-model/location';
+import { ColorTheme, LocationColor } from '../color';
+import { ParamDefinition as PD } from 'mol-util/param-definition'
+import { ThemeDataContext } from 'mol-theme/theme';
+import { ColorListOptions, ColorListName } from 'mol-util/color/scale';
+import { Column } from 'mol-data/db';
+import { Entities } from 'mol-model/structure/model/properties/common';
+
+const DefaultColor = Color(0xCCCCCC)
+const Description = 'Gives every polymer chain a color based on its `asym_id` value.'
+
+export const PolymerIdColorThemeParams = {
+    list: PD.Select<ColorListName>('RdYlBu', ColorListOptions),
+}
+export function getPolymerIdColorThemeParams(ctx: ThemeDataContext) {
+    return PolymerIdColorThemeParams // TODO return copy
+}
+export type PolymerIdColorThemeProps = PD.Values<typeof PolymerIdColorThemeParams>
+
+function getAsymId(unit: Unit): StructureElement.Property<string> {
+    switch (unit.kind) {
+        case Unit.Kind.Atomic:
+            return StructureProperties.chain.label_asym_id
+        case Unit.Kind.Spheres:
+        case Unit.Kind.Gaussians:
+            return StructureProperties.coarse.asym_id
+    }
+}
+
+function addPolymerAsymIds(map: Map<string, number>, asymId: Column<string>, entityId: Column<string>, entities: Entities) {
+    let j = map.size
+    for (let o = 0, ol = asymId.rowCount; o < ol; ++o) {
+        const e = entityId.value(o)
+        const eI = entities.getEntityIndex(e)
+        if (entities.data.type.value(eI) === 'polymer') {
+            const k = asymId.value(o)
+            if (!map.has(k)) {
+                map.set(k, j)
+                j += 1
+            }
+        }
+    }
+}
+
+export function PolymerIdColorTheme(ctx: ThemeDataContext, props: PolymerIdColorThemeProps): ColorTheme<PolymerIdColorThemeProps> {
+    let color: LocationColor
+    const scale = ColorScale.create({ listOrName: props.list, minLabel: 'Start', maxLabel: 'End' })
+
+    if (ctx.structure) {
+        const l = StructureElement.create()
+        const { models } = ctx.structure
+        const polymerAsymIdSerialMap = new Map<string, number>()
+        for (let i = 0, il = models.length; i <il; ++i) {
+            for (let i = 0, il = models.length; i <il; ++i) {
+                const m = models[i]
+                addPolymerAsymIds(polymerAsymIdSerialMap, m.atomicHierarchy.chains.label_asym_id, m.atomicHierarchy.chains.label_entity_id, m.entities)
+                if (m.coarseHierarchy.isDefined) {
+                    addPolymerAsymIds(polymerAsymIdSerialMap, m.coarseHierarchy.spheres.asym_id, m.coarseHierarchy.spheres.entity_id, m.entities)
+                    addPolymerAsymIds(polymerAsymIdSerialMap, m.coarseHierarchy.gaussians.asym_id, m.coarseHierarchy.spheres.entity_id, m.entities)
+                }
+            }
+        }
+        scale.setDomain(0, polymerAsymIdSerialMap.size - 1)
+        const scaleColor = scale.color
+
+        color = (location: Location): Color => {
+            if (StructureElement.isLocation(location)) {
+                const asym_id = getAsymId(location.unit)
+                return scaleColor(polymerAsymIdSerialMap.get(asym_id(location)) || 0)
+            } else if (Link.isLocation(location)) {
+                const asym_id = getAsymId(location.aUnit)
+                l.unit = location.aUnit
+                l.element = location.aUnit.elements[location.aIndex]
+                return scaleColor(polymerAsymIdSerialMap.get(asym_id(l)) || 0)
+            }
+            return DefaultColor
+        }
+    } else {
+        color = () => DefaultColor
+    }
+
+    return {
+        granularity: 'group',
+        color,
+        props,
+        description: Description,
+        legend: scale ? scale.legend : undefined
+    }
+}
+
+export const PolymerIdColorThemeProvider: ColorTheme.Provider<typeof PolymerIdColorThemeParams> = {
+    label: 'Polymer Id',
+    factory: PolymerIdColorTheme,
+    getParams: getPolymerIdColorThemeParams
+}
\ No newline at end of file