diff --git a/src/mol-model/structure/structure/element.ts b/src/mol-model/structure/structure/element.ts
index 8ac7af0c113873bfc35d6fae413435400d17e115..2630573e46291f6f11c7ddc05807f52c2afdff48 100644
--- a/src/mol-model/structure/structure/element.ts
+++ b/src/mol-model/structure/structure/element.ts
@@ -139,6 +139,8 @@ namespace StructureElement {
         }
 
         export function remap(loci: Loci, structure: Structure): Loci {
+            if (structure === loci.structure) return loci
+
             return Loci(structure, loci.elements.map(e => ({
                 unit: structure.unitMap.get(e.unit.id)!,
                 indices: e.indices
diff --git a/src/mol-plugin/ui/sequence.tsx b/src/mol-plugin/ui/sequence.tsx
index caab759f3f073d6d9fe30b9ff0077228ca5a299a..82cbdd76bee45b604aba4ba7e1903a80ff289975 100644
--- a/src/mol-plugin/ui/sequence.tsx
+++ b/src/mol-plugin/ui/sequence.tsx
@@ -11,12 +11,13 @@ import { StateTreeSpine } from '../../mol-state/tree/spine';
 import { PluginStateObject as SO } from '../state/objects';
 import { Sequence } from './sequence/sequence';
 import { Structure, StructureElement, StructureProperties as SP } from '../../mol-model/structure';
-import { SequenceWrapper } from './sequence/util';
+import { SequenceWrapper } from './sequence/wrapper';
 import { PolymerSequenceWrapper } from './sequence/polymer';
 import { StructureElementSelectionManager } from '../util/structure-element-selection';
 import { MarkerAction } from '../../mol-util/marker-action';
 import { ParameterControls } from './controls/parameters';
 import { ParamDefinition as PD } from '../../mol-util/param-definition';
+import { HeteroSequenceWrapper } from './sequence/hetero';
 
 function opKey(l: StructureElement) {
     const ids = SP.unit.pdbx_struct_oper_list_ids(l)
@@ -27,19 +28,16 @@ function opKey(l: StructureElement) {
 }
 
 function getSequenceWrapper(state: SequenceViewState, structureSelection: StructureElementSelectionManager): SequenceWrapper.Any | undefined {
-    const { structure, entity, chain, operator } = state
+    const { structure, entityId, invariantUnitId, operatorKey } = state
     const l = StructureElement.create()
-    for (let i = 0, il = structure.units.length; i < il; ++i) {
-        const unit = structure.units[i]
-        if (unit.polymerElements.length === 0) continue
-
+    for (const unit of structure.units) {
         StructureElement.set(l, unit, unit.elements[0])
-        if (SP.entity.id(l) !== entity) continue
-        if (SP.chain.label_asym_id(l) !== chain) continue
-        if (opKey(l) !== operator) continue
+        if (SP.entity.id(l) !== entityId) continue
+        if (unit.invariantId !== invariantUnitId) continue
+        if (opKey(l) !== operatorKey) continue
 
-        // console.log('new PolymerSequenceWrapper', structureSelection.get(structure))
-        const sw = new PolymerSequenceWrapper({ structure, unit })
+        const Wrapper = unit.polymerElements.length ? PolymerSequenceWrapper : HeteroSequenceWrapper
+        const sw = new Wrapper({ structure, unit })
         sw.markResidue(structureSelection.get(structure), MarkerAction.Select)
         return sw
     }
@@ -50,74 +48,76 @@ function getEntityOptions(structure: Structure) {
     const l = StructureElement.create()
     const seen = new Set<string>()
 
-    structure.units.forEach(unit => {
-        if (unit.polymerElements.length === 0) return
-
+    for (const unit of structure.units) {
         StructureElement.set(l, unit, unit.elements[0])
         const id = SP.entity.id(l)
-        if (seen.has(id)) return
+        if (seen.has(id)) continue
 
         const label = `${id}: ${SP.entity.pdbx_description(l).join(', ')}`
         options.push([ id, label ])
         seen.add(id)
-    })
+    }
 
     if (options.length === 0) options.push(['', 'No entities'])
     return options
 }
 
 function getChainOptions(structure: Structure, entityId: string) {
-    const options: [string, string][] = []
+    const options: [number, string][] = []
     const l = StructureElement.create()
-    const seen = new Set<string>()
-
-    structure.units.forEach(unit => {
-        if (unit.polymerElements.length === 0) return
+    const seen = new Set<number>()
+    const water = new Map<string, number>()
 
+    for (const unit of structure.units) {
         StructureElement.set(l, unit, unit.elements[0])
-        if (SP.entity.id(l) !== entityId) return
+        if (SP.entity.id(l) !== entityId) continue
+
+        const id = unit.invariantId
+        if (seen.has(id)) continue
 
-        const id = SP.chain.label_asym_id(l)
-        if (seen.has(id)) return
+        let label = `${SP.chain.label_asym_id(l)}: ${SP.chain.auth_asym_id(l)}`
+        if (SP.entity.type(l) === 'water') {
+            const count = water.get(label) || 1
+            water.set(label, count + 1)
+            label += ` #${count}`
+        }
 
-        const label = `${id}: ${SP.chain.auth_asym_id(l)}`
         options.push([ id, label ])
         seen.add(id)
-    })
+    }
 
-    if (options.length === 0) options.push(['', 'No chains'])
+    if (options.length === 0) options.push([-1, 'No chains'])
     return options
 }
 
-function getOperatorOptions(structure: Structure, entityId: string, label_asym_id: string) {
+function getOperatorOptions(structure: Structure, entityId: string, invariantUnitId: number) {
     const options: [string, string][] = []
     const l = StructureElement.create()
     const seen = new Set<string>()
 
-    structure.units.forEach(unit => {
-        if (unit.polymerElements.length === 0) return
+    for (const unit of structure.units) {
         StructureElement.set(l, unit, unit.elements[0])
-        if (SP.entity.id(l) !== entityId) return
-        if (SP.chain.label_asym_id(l) !== label_asym_id) return
+        if (SP.entity.id(l) !== entityId) continue
+        if (unit.invariantId !== invariantUnitId) continue
 
         const id = opKey(l)
-        if (seen.has(id)) return
+        if (seen.has(id)) continue
 
         const label = unit.conformation.operator.name
         options.push([ id, label ])
         seen.add(id)
-    })
+    }
 
     if (options.length === 0) options.push(['', 'No operators'])
     return options
 }
 
-type SequenceViewState = { structure: Structure, entity: string, chain: string, operator: string }
+type SequenceViewState = { structure: Structure, entityId: string, invariantUnitId: number, operatorKey: string }
 
 export class SequenceView extends PluginUIComponent<{ }, SequenceViewState> {
     private spine: StateTreeSpine.Impl
 
-    state = { structure: Structure.Empty, entity: '', chain: '', operator: '' }
+    state = { structure: Structure.Empty, entityId: '', invariantUnitId: -1, operatorKey: '' }
 
     constructor(props: {}, context?: any) {
         super(props, context);
@@ -151,17 +151,17 @@ export class SequenceView extends PluginUIComponent<{ }, SequenceViewState> {
 
     private getInitialState(): SequenceViewState {
         const structure = this.getStructure()
-        const entity = getEntityOptions(structure)[0][0]
-        const chain = getChainOptions(structure, entity)[0][0]
-        const operator = getOperatorOptions(structure, entity, chain)[0][0]
-        return { structure, entity, chain, operator }
+        const entityId = getEntityOptions(structure)[0][0]
+        const invariantUnitId = getChainOptions(structure, entityId)[0][0]
+        const operatorKey = getOperatorOptions(structure, entityId, invariantUnitId)[0][0]
+        return { structure, entityId, invariantUnitId, operatorKey }
     }
 
     private get params() {
-        const { structure, entity, chain } = this.state
+        const { structure, entityId, invariantUnitId } = this.state
         const entityOptions = getEntityOptions(structure)
-        const chainOptions = getChainOptions(structure, entity)
-        const operatorOptions = getOperatorOptions(structure, entity, chain)
+        const chainOptions = getChainOptions(structure, entityId)
+        const operatorOptions = getOperatorOptions(structure, entityId, invariantUnitId)
         return {
             entity: PD.Select(entityOptions[0][0], entityOptions),
             chain: PD.Select(chainOptions[0][0], chainOptions),
@@ -169,20 +169,29 @@ export class SequenceView extends PluginUIComponent<{ }, SequenceViewState> {
         }
     }
 
+    private get values(): PD.Values<SequenceView['params']> {
+        return {
+            entity: this.state.entityId,
+            chain: this.state.invariantUnitId,
+            operator: this.state.operatorKey
+        }
+    }
+
+    // TODO try to use selected option from previous state
     private setParamProps = (p: { param: PD.Base<any>, name: string, value: any }) => {
         const state = { ...this.state }
         switch (p.name) {
             case 'entity':
-                state.entity = p.value
-                state.chain = getChainOptions(state.structure, state.entity)[0][0]
-                state.operator = getOperatorOptions(state.structure, state.entity, state.chain)[0][0]
+                state.entityId = p.value
+                state.invariantUnitId = getChainOptions(state.structure, state.entityId)[0][0]
+                state.operatorKey = getOperatorOptions(state.structure, state.entityId, state.invariantUnitId)[0][0]
                 break
             case 'chain':
-                state.chain = p.value
-                state.operator = getOperatorOptions(state.structure, state.entity, state.chain)[0][0]
+                state.invariantUnitId = p.value
+                state.operatorKey = getOperatorOptions(state.structure, state.entityId, state.invariantUnitId)[0][0]
                 break
             case 'operator':
-                state.operator = p.value
+                state.operatorKey = p.value
                 break
         }
         this.setState(state)
@@ -196,7 +205,7 @@ export class SequenceView extends PluginUIComponent<{ }, SequenceViewState> {
         const sequenceWrapper = this.getSequenceWrapper()
         return <div className='msp-sequence'>
             <div className='msp-sequence-select'>
-                <ParameterControls params={this.params} values={this.state} onChange={this.setParamProps} />
+                <ParameterControls params={this.params} values={this.values} onChange={this.setParamProps} />
             </div>
             {sequenceWrapper !== undefined
                 ? <Sequence sequenceWrapper={sequenceWrapper} />
diff --git a/src/mol-plugin/ui/sequence/hetero.ts b/src/mol-plugin/ui/sequence/hetero.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d0e7d4d726e30cc3fe7c37ab00c3b38aab21cb62
--- /dev/null
+++ b/src/mol-plugin/ui/sequence/hetero.ts
@@ -0,0 +1,83 @@
+/**
+ * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { Structure, StructureElement, ResidueIndex } from '../../../mol-model/structure';
+import { SequenceWrapper, StructureUnit } from './wrapper';
+import { OrderedSet, Segmentation, Interval, SortedArray } from '../../../mol-data/int';
+import { Loci } from '../../../mol-model/loci';
+import { ColorNames } from '../../../mol-util/color/tables';
+
+export class HeteroSequenceWrapper extends SequenceWrapper<StructureUnit> {
+    private readonly sequence: string[]
+    private readonly sequenceIndices: Map<ResidueIndex, number>
+    private readonly residueIndices: Map<number, ResidueIndex>
+
+    residueLabel(seqIdx: number) {
+        return this.sequence[seqIdx]
+    }
+    residueColor(seqIdx: number) {
+        return ColorNames.black
+    }
+
+    eachResidue(loci: Loci, apply: (set: OrderedSet) => boolean) {
+        let changed = false
+        const { structure, unit } = this.data
+        if (StructureElement.isLoci(loci)) {
+            if (!Structure.areParentsEqual(loci.structure, structure)) return false
+
+            for (const e of loci.elements) {
+                if (e.unit.id === unit.id) {
+                    const { index: residueIndex } = e.unit.model.atomicHierarchy.residueAtomSegments
+                    OrderedSet.forEach(e.indices, v => {
+                        const seqIdx = this.sequenceIndices.get(residueIndex[unit.elements[v]])
+                        if (seqIdx !== undefined && apply(Interval.ofSingleton(seqIdx))) changed = true
+                    })
+                }
+            }
+        } else if (Structure.isLoci(loci)) {
+            if (!Structure.areParentsEqual(loci.structure, structure)) return false
+
+            if (apply(Interval.ofBounds(0, this.length))) changed = true
+        }
+        return changed
+    }
+
+    getLoci(seqIdx: number) {
+        const elements: StructureElement.Loci['elements'][0][] = []
+        const rI = this.residueIndices.get(seqIdx)
+        if (rI !== undefined) {
+            const { unit } = this.data
+            const { offsets } = unit.model.atomicHierarchy.residueAtomSegments
+            const start = SortedArray.findPredecessorIndex(unit.elements, offsets[rI])
+            const end = SortedArray.findPredecessorIndex(unit.elements, offsets[rI + 1])
+            elements.push({ unit, indices: Interval.ofBounds(start, end) })
+        }
+        return StructureElement.Loci(this.data.structure, elements)
+    }
+
+    constructor(data: StructureUnit) {
+        const sequence: string[] = []
+        const sequenceIndices = new Map<ResidueIndex, number>()
+        const residueIndices = new Map<number, ResidueIndex>()
+
+        const residueIt = Segmentation.transientSegments(data.unit.model.atomicHierarchy.residueAtomSegments, data.unit.elements)
+        while (residueIt.hasNext) {
+            const { index } = residueIt.move()
+            sequenceIndices.set(index, sequence.length)
+            residueIndices.set(sequence.length, index)
+            sequence.push(data.unit.model.atomicHierarchy.residues.label_comp_id.value(index))
+        }
+
+        const length = sequence.length
+        const markerArray = new Uint8Array(length)
+
+        super(data, markerArray, length)
+
+        this.sequence = sequence
+        this.sequenceIndices = sequenceIndices
+        this.residueIndices = residueIndices
+    }
+}
\ No newline at end of file
diff --git a/src/mol-plugin/ui/sequence/polymer.ts b/src/mol-plugin/ui/sequence/polymer.ts
index 6a63b0bdf154306212e56a539a678df26a337b93..b86f783defd3b14cbc4d22314d297a667cd93db5 100644
--- a/src/mol-plugin/ui/sequence/polymer.ts
+++ b/src/mol-plugin/ui/sequence/polymer.ts
@@ -5,15 +5,13 @@
  */
 
 import { StructureSelection, StructureQuery, Structure, Queries, StructureProperties as SP, StructureElement, Unit, ElementIndex } from '../../../mol-model/structure';
-import { SequenceWrapper } from './util';
+import { SequenceWrapper, StructureUnit } from './wrapper';
 import { OrderedSet, Interval, SortedArray } from '../../../mol-data/int';
 import { Loci } from '../../../mol-model/loci';
 import { Sequence } from '../../../mol-model/sequence';
 import { MissingResidues } from '../../../mol-model/structure/model/properties/common';
 import { ColorNames } from '../../../mol-util/color/tables';
 
-export type StructureUnit = { structure: Structure, unit: Unit }
-
 export class PolymerSequenceWrapper extends SequenceWrapper<StructureUnit> {
     private readonly sequence: Sequence
     private readonly missing: MissingResidues
@@ -25,6 +23,7 @@ export class PolymerSequenceWrapper extends SequenceWrapper<StructureUnit> {
     seqId(seqIdx: number) {
         return this.sequence.offset + seqIdx + 1
     }
+
     residueLabel(seqIdx: number) {
         return this.sequence.sequence[seqIdx]
     }
@@ -55,8 +54,8 @@ export class PolymerSequenceWrapper extends SequenceWrapper<StructureUnit> {
         return changed
     }
 
-    getLoci(seqId: number) {
-        const query = createResidueQuery(this.data.unit.id, seqId);
+    getLoci(seqIdx: number) {
+        const query = createResidueQuery(this.data.unit.id, this.seqId(seqIdx));
         return StructureSelection.toLoci2(StructureQuery.run(query, this.data.structure));
     }
 
@@ -66,7 +65,7 @@ export class PolymerSequenceWrapper extends SequenceWrapper<StructureUnit> {
         const length = sequence.sequence.length
         const markerArray = new Uint8Array(length)
 
-        super(data, markerArray, sequence.sequence.length)
+        super(data, markerArray, length)
 
         this.sequence = sequence
         this.missing = data.unit.model.properties.missingResidues
diff --git a/src/mol-plugin/ui/sequence/residue.tsx b/src/mol-plugin/ui/sequence/residue.tsx
index 1d543db7742ee63acff131146ba66aa4b134d9ba..6e9d19a262f3032c3aae454a61dcbc510c55b48f 100644
--- a/src/mol-plugin/ui/sequence/residue.tsx
+++ b/src/mol-plugin/ui/sequence/residue.tsx
@@ -11,11 +11,11 @@ import { getButtons, getModifiers } from '../../../mol-util/input/input-observer
 import { Sequence } from './sequence';
 import { Color } from '../../../mol-util/color';
 
-export class Residue extends PurePluginUIComponent<{ seqId: number, label: string, parent: Sequence<any>, marker: number, color: Color }> {
+export class Residue extends PurePluginUIComponent<{ seqIdx: number, label: string, parent: Sequence<any>, marker: number, color: Color }> {
 
     mouseEnter = (e: React.MouseEvent) => {
         const modifiers = getModifiers(e.nativeEvent)
-        this.props.parent.highlight(this.props.seqId, modifiers);
+        this.props.parent.highlight(this.props.seqIdx, modifiers);
     }
 
     mouseLeave = () => {
@@ -25,11 +25,11 @@ export class Residue extends PurePluginUIComponent<{ seqId: number, label: strin
     mouseDown = (e: React.MouseEvent) => {
         const buttons = getButtons(e.nativeEvent)
         const modifiers = getModifiers(e.nativeEvent)
-        this.props.parent.click(this.props.seqId, buttons, modifiers);
+        this.props.parent.click(this.props.seqIdx, buttons, modifiers);
         e.stopPropagation() // so that `parent.mouseDown` is not called
     }
 
-    getBackgroundColor() {
+    get backgroundColor() {
         // TODO make marker color configurable
         if (this.props.marker === 0) return ''
         if (this.props.marker % 2 === 0) return 'rgb(51, 255, 25)' // selected
@@ -37,6 +37,12 @@ export class Residue extends PurePluginUIComponent<{ seqId: number, label: strin
         return 'rgb(255, 102, 153)' // highlighted
     }
 
+    get margin() {
+        return this.props.label.length > 1 && this.props.seqIdx
+            ? `0px 0px 0px 4px`
+            : undefined
+    }
+
     render() {
         return <span
             onMouseEnter={this.mouseEnter}
@@ -44,7 +50,8 @@ export class Residue extends PurePluginUIComponent<{ seqId: number, label: strin
             onMouseDown={this.mouseDown}
             style={{
                 color: Color.toStyle(this.props.color),
-                backgroundColor: this.getBackgroundColor()
+                backgroundColor: this.backgroundColor,
+                margin: this.margin
             }}>
             {this.props.label}
         </span>;
diff --git a/src/mol-plugin/ui/sequence/sequence.tsx b/src/mol-plugin/ui/sequence/sequence.tsx
index 913cbd9e2c2596a22d88be481c7740339604c468..2d1528bc11a77d88016310b099a5f5f19a229b55 100644
--- a/src/mol-plugin/ui/sequence/sequence.tsx
+++ b/src/mol-plugin/ui/sequence/sequence.tsx
@@ -12,7 +12,7 @@ import { MarkerAction } from '../../../mol-util/marker-action';
 import { ButtonsType, ModifiersKeys, getButtons, getModifiers } from '../../../mol-util/input/input-observer';
 import { ValueBox } from '../../../mol-util';
 import { Residue } from './residue';
-import { SequenceWrapper } from './util';
+import { SequenceWrapper } from './wrapper';
 
 type SequenceProps = { sequenceWrapper: SequenceWrapper.Any }
 type SequenceState = { markerData: ValueBox<Uint8Array> }
@@ -93,7 +93,7 @@ export class Sequence<P extends SequenceProps> extends PluginUIComponent<P, Sequ
         const elems: JSX.Element[] = [];
         for (let i = 0, il = sw.length; i < il; ++i) {
             elems[elems.length] = <Residue
-                seqId={sw.seqId(i)}
+                seqIdx={i}
                 label={sw.residueLabel(i)}
                 parent={this}
                 marker={markerData.value[i]}
diff --git a/src/mol-plugin/ui/sequence/util.ts b/src/mol-plugin/ui/sequence/wrapper.ts
similarity index 83%
rename from src/mol-plugin/ui/sequence/util.ts
rename to src/mol-plugin/ui/sequence/wrapper.ts
index 158b4729468f2ea7c51c843e391a348c141a154f..275b315a143ff5153e3ceb85597d867b85eebc0e 100644
--- a/src/mol-plugin/ui/sequence/util.ts
+++ b/src/mol-plugin/ui/sequence/wrapper.ts
@@ -7,18 +7,19 @@
 import { OrderedSet } from '../../../mol-data/int';
 import { Loci } from '../../../mol-model/loci';
 import { MarkerAction, applyMarkerAction } from '../../../mol-util/marker-action';
-import { StructureElement } from '../../../mol-model/structure';
+import { StructureElement, Structure, Unit } from '../../../mol-model/structure';
 import { Color } from '../../../mol-util/color';
 
+export type StructureUnit = { structure: Structure, unit: Unit }
+
 export { SequenceWrapper }
 
 abstract class SequenceWrapper<D> {
-    abstract seqId(seqIdx: number): number
     abstract residueLabel(seqIdx: number): string
     abstract residueColor(seqIdx: number): Color
 
     abstract eachResidue(loci: Loci, apply: (set: OrderedSet) => boolean): boolean
-    abstract getLoci(seqId: number): StructureElement.Loci
+    abstract getLoci(seqIdx: number): StructureElement.Loci
 
     markResidue(loci: Loci, action: MarkerAction) {
         return this.eachResidue(loci, (set: OrderedSet) => {
diff --git a/src/mol-plugin/util/interactivity.ts b/src/mol-plugin/util/interactivity.ts
index dac8ca4bcb38543830e3795a29e2c304a303798a..87031ce0e1c0f76fe4f3189267579a5fd662ba1e 100644
--- a/src/mol-plugin/util/interactivity.ts
+++ b/src/mol-plugin/util/interactivity.ts
@@ -98,9 +98,11 @@ namespace Interactivity {
             }
             loci = Granularity[this.props.granularity](loci)
             if (Structure.isLoci(loci)) {
-                loci = Structure.toStructureElementLoci(loci)
+                // convert to StructureElement.Loci of root structure
+                loci = Structure.toStructureElementLoci(Structure.Loci(loci.structure.parent || loci.structure))
             }
             if (StructureElement.isLoci(loci) && loci.structure.parent) {
+                // ensure the root structure is used
                 loci = StructureElement.Loci.remap(loci, loci.structure.parent)
             }
             return { loci, repr }