diff --git a/src/common/graph.ts b/src/common/graph.ts
index d515c4fd5900b0fc16df3fdbc2f9e6a545aa1e8a..4ed5997d679bcad99fb48afc774b6ae3e9ad6069 100644
--- a/src/common/graph.ts
+++ b/src/common/graph.ts
@@ -1,28 +1,42 @@
 import * as Config from "../config";
 
-interface Link {
+interface LinkData {
     source: string;
     target: string;
     type?: string;
 }
 
-export interface LinkData {
-    source: NodeData;
-    target: NodeData;
-    type?: string;
+export interface Link {
+    source: Node;
+    target: Node;
+    type?: GraphObjectType;
 }
 
-export interface NodeData {
-    id: string;
+interface NodeContent {
     name: string;
     description?: string;
     icon?: string;
     banner?: string;
-    type?: string;
     video?: string;
     references?: string[];
-    neighbors: NodeData[];
-    links: LinkData[];
+}
+
+interface NodeData extends NodeContent {
+    id: string;
+    type?: string;
+}
+
+export interface Node extends NodeContent {
+    id: string;
+    type: GraphObjectType;
+
+    neighbors: Node[];
+    links: Link[];
+}
+
+export interface GraphObjectType {
+    name: string;
+    color?: string;
 }
 
 export interface Coordinate {
@@ -35,42 +49,52 @@ export interface Coordinate {
  * Basic graph data structure.
  */
 export default class Graph {
-    public nodes: NodeData[];
-    public links: LinkData[];
-    private idToNode: Map<string, NodeData>;
-    public edgeColors: Map<string, string>;
-    public nodeColors: Map<string, string>;
-
-    constructor(nodes: NodeData[], links: Link[]) {
-        this.nodes = nodes;
-        this.idToNode = new Map<string, NodeData>();
-        nodes.forEach((node) => {
-            this.idToNode.set(node.id, node);
-        });
+    public nodes: Node[];
+    public links: Link[];
+    public objectGroups: GraphObjectType[];
+    public nameToObjectGroup: Map<string, GraphObjectType>;
+    private idToNode: Map<string, Node>;
+
+    constructor(
+        nodes: NodeData[],
+        links: LinkData[],
+        objectGroups?: GraphObjectType[]
+    ) {
+        this.objectGroups = objectGroups ?? this.createObjectGroups(nodes);
+
+        this.nameToObjectGroup = new Map<string, GraphObjectType>();
+        this.objectGroups.forEach((group) =>
+            this.nameToObjectGroup.set(group.name, group)
+        );
+
+        this.createNodes(nodes);
 
         this.links = links.map((link) => {
             return {
                 source: this.idToNode.get(link.source),
                 target: this.idToNode.get(link.target),
-                type: link.type,
             };
         });
 
-        this.edgeColors = new Map<string, string>();
-        this.nodeColors = new Map<string, string>();
-
-        this.resetNodeData();
         this.updateNodeData();
         this.removeFloatingNodes();
-        this.mapNodeColors();
-        this.mapLinkColors();
     }
 
-    private resetNodeData() {
-        for (const node of this.nodes) {
+    private createNodes(nodes: NodeData[]) {
+        this.nodes = [];
+        for (const nodeData of nodes) {
+            const { type, ...nodeVars } = nodeData;
+            const node = { ...nodeVars } as Node;
+            node.type = this.nameToObjectGroup.get(type);
             node.neighbors = [];
             node.links = [];
+            this.nodes.push(node);
         }
+
+        this.idToNode = new Map<string, Node>();
+        this.nodes.forEach((node) => {
+            this.idToNode.set(node.id, node);
+        });
     }
 
     private removeFloatingNodes() {
@@ -82,8 +106,6 @@ export default class Graph {
      * Creates a 'neighbors' and 'links' array for each node object.
      */
     private updateNodeData() {
-        this.resetNodeData();
-
         this.links.forEach((link) => {
             const a = link.source;
             const b = link.target;
@@ -94,82 +116,64 @@ export default class Graph {
         });
     }
 
-    public node(id: string): NodeData {
+    public node(id: string): Node {
         return this.idToNode.get(id);
     }
 
-    /**
-     * Maps the colors of the color palette to the different edge types
-     */
-    private mapLinkColors() {
-        // TODO: Legacy - is there a use-case for link types?
-        const linkClasses = this.getLinkClasses();
-        for (let i = 0; i < linkClasses.length; i++) {
-            this.edgeColors.set(
-                linkClasses[i],
-                Config.COLOR_PALETTE[i % Config.COLOR_PALETTE.length]
-            );
-        }
-    }
-
-    /**
-     * Maps the colors of the color palette to the different edge types
-     */
-    private mapNodeColors() {
-        const nodeClasses = this.getNodeClasses();
-        for (let i = 0; i < nodeClasses.length; i++) {
-            this.nodeColors.set(
-                nodeClasses[i],
-                Config.COLOR_PALETTE[i % Config.COLOR_PALETTE.length]
-            );
+    private createObjectGroups(nodes: NodeData[]): GraphObjectType[] {
+        const objectGroups: GraphObjectType[] = [];
+        const nodeClasses: string[] = [];
+        nodes.forEach((node) => nodeClasses.push(node.type));
+        const nodeTypes = [...new Set(nodeClasses)].map((c) => String(c));
+
+        for (let i = 0; i < nodeTypes.length; i++) {
+            objectGroups.push({
+                name: nodeTypes[i],
+                color: Config.COLOR_PALETTE[i % Config.COLOR_PALETTE.length],
+            });
         }
+        return objectGroups;
     }
 
-    /**
-     * Returns an array containing the different edge types of the graph.
-     * @returns {*[]}
-     */
-    public getLinkClasses(): string[] {
-        const linkClasses: string[] = [];
-
-        this.links.forEach((link) => linkClasses.push(link.type));
-        return [...new Set(linkClasses)].map((c) => String(c));
-    }
-
-    public getNodeClasses(): string[] {
-        const nodeClasses: string[] = [];
-        this.nodes.forEach((node) => nodeClasses.push(node.type));
-        return [...new Set(nodeClasses)].map((c) => String(c));
-    }
     public view(
         nodeTypes: Map<string, boolean>,
         linkTypes?: Map<string, boolean>
     ): Graph {
         // Filter nodes depending on type
-        const nodes = this.nodes.filter((l) => nodeTypes.get(l.type));
+        const nodes = this.nodes.filter((l) => nodeTypes.get(l.type.name));
 
         // Filter links depending on type
         let links;
         if (linkTypes === undefined) {
             links = this.links;
         } else {
-            links = this.links.filter((l) => linkTypes.get(l.type));
+            links = this.links.filter((l) => linkTypes.get(l.type.name));
         }
 
         // Filter links which are connected to an invisible node
         links = links.filter(
-            (l) => nodeTypes.get(l.source.type) && nodeTypes.get(l.target.type)
+            (l) =>
+                nodeTypes.get(l.source.type.name) &&
+                nodeTypes.get(l.target.type.name)
         );
 
+        // Convert to data objects and create new graph.
+        // Using spread syntax to simplify object copying.
         return new Graph(
-            nodes,
+            nodes.map((node) => {
+                // eslint-disable-next-line no-unused-vars
+                const { type, neighbors, links, ...nodeVars } = node;
+                const nodeData = { ...nodeVars } as NodeData;
+                nodeData.type = type.name;
+                return nodeData;
+            }),
             links.map((link) => {
                 return {
                     source: link.source.id,
                     target: link.target.id,
-                    type: link.type,
                 };
-            })
+            }),
+            this.objectGroups
         );
     }
 }
diff --git a/src/display/components/nodefilter/filtermenu.tsx b/src/display/components/nodefilter/filtermenu.tsx
index a78fc93a35e695a30523ffdf11386c54af48341c..f38c8affb945dd898768c0a4f0e7c05ed93d9f44 100644
--- a/src/display/components/nodefilter/filtermenu.tsx
+++ b/src/display/components/nodefilter/filtermenu.tsx
@@ -2,9 +2,10 @@ import React, { useState } from "react";
 
 import "./filtermenu.css";
 import Label from "./label";
+import { GraphObjectType } from "../../../common/graph";
 
 interface FilterMenuProps {
-    classes: Map<string, string>;
+    classes: Map<string, GraphObjectType>;
     onVisibilityChange?: (visibility: Map<string, boolean>) => void;
 }
 
@@ -47,7 +48,7 @@ function FilterMenu({ classes, onVisibilityChange }: FilterMenuProps) {
                 <Label
                     key={cls}
                     text={cls}
-                    color={classes.get(cls)}
+                    color={classes.get(cls).color}
                     width={labelWidth}
                     active={visibility[idx]}
                     onClick={() => handleClick(idx)}
diff --git a/src/display/components/nodeinfo/neighbors.tsx b/src/display/components/nodeinfo/neighbors.tsx
index b7f713ec0c1e237e711b03a2845144daac357c42..5a899cc6a066bdf9c4ccbdf169eac197d8125b4e 100644
--- a/src/display/components/nodeinfo/neighbors.tsx
+++ b/src/display/components/nodeinfo/neighbors.tsx
@@ -1,15 +1,15 @@
 import React from "react";
 
-import { NodeData } from "../../../common/graph";
+import { GraphObjectType, Node } from "../../../common/graph";
 import FancyScrollbar from "../fancyscrollbar";
 import Collapsible from "../collapsible";
 
 import "./neighbors.css";
 
 interface NeighborsProps {
-    neighbors: NodeData[];
-    nodeColors?: Map<string, string>;
-    nodeClickedCallback?: (node: NodeData) => void;
+    neighbors: Node[];
+    nodeColors?: Map<string, GraphObjectType>;
+    nodeClickedCallback?: (node: Node) => void;
 }
 
 /**
@@ -22,21 +22,23 @@ interface NeighborsProps {
 function Neighbors({
     neighbors,
     nodeClickedCallback,
-    nodeColors = new Map<string, string>(),
+    nodeColors = new Map<string, GraphObjectType>(),
 }: NeighborsProps) {
-    const classes = [...new Set<string>(neighbors.map((node) => node.type))];
+    const classes = [
+        ...new Set<string>(neighbors.map((node) => node.type.name)),
+    ];
     classes.sort(); // Sort classes to get a constant order of the node type tabs
-    const categories = new Map<string, Array<NodeData>>();
+    const categories = new Map<string, Array<Node>>();
 
     for (const cls of classes) {
         categories.set(cls, []);
     }
 
     for (const neighbor of neighbors) {
-        categories.get(neighbor.type).push(neighbor);
+        categories.get(neighbor.type.name).push(neighbor);
     }
 
-    const handleNodeClick = (node: NodeData) => {
+    const handleNodeClick = (node: Node) => {
         if (nodeClickedCallback) {
             nodeClickedCallback(node);
         }
@@ -51,7 +53,7 @@ function Neighbors({
                             header={cls}
                             key={cls}
                             heightTransition={false}
-                            color={nodeColors.get(cls)}
+                            color={nodeColors.get(cls).color}
                         >
                             <ul>
                                 {categories.get(cls).map((node) => (
diff --git a/src/display/components/nodeinfo/nodeinfobar.tsx b/src/display/components/nodeinfo/nodeinfobar.tsx
index 9d98adda3e33ac859d861a242700ad8682c9131c..4965e738d90c1df5985d6912d64b04178bfc8d54 100644
--- a/src/display/components/nodeinfo/nodeinfobar.tsx
+++ b/src/display/components/nodeinfo/nodeinfobar.tsx
@@ -1,7 +1,7 @@
 import React from "react";
 
 import "./nodeinfobar.css";
-import { NodeData } from "../../../common/graph";
+import { GraphObjectType, Node } from "../../../common/graph";
 import TitleArea from "./titlearea";
 import FancyScrollbar from "../fancyscrollbar";
 import MediaArea from "./mediaarea";
@@ -9,10 +9,10 @@ import Neighbors from "./neighbors";
 
 interface InfoBarProps {
     height: number;
-    node: NodeData;
-    nodeColors?: Map<string, string>;
+    node: Node;
+    nodeColors?: Map<string, GraphObjectType>;
     onClose?: () => void;
-    nodeClickedCallback?: (node: NodeData) => void;
+    nodeClickedCallback?: (node: Node) => void;
 }
 
 /**
diff --git a/src/display/components/searchbar.tsx b/src/display/components/searchbar.tsx
index 9cfca31d869ab6089ce56f027b3a762fe6e73568..d1ee95ed29853234c5c2d4cfa389c8b737138f47 100644
--- a/src/display/components/searchbar.tsx
+++ b/src/display/components/searchbar.tsx
@@ -3,12 +3,12 @@ import React, { useEffect, useRef, useState } from "react";
 import "./searchbar.css";
 import searchicon from "./search_icon.svg";
 import closeicon from "./close_icon.svg";
-import { NodeData } from "../../common/graph";
+import { Node } from "../../common/graph";
 
 interface SearchBarProps {
     minified: boolean;
-    nodeSet: NodeData[];
-    onSearch?: (node: NodeData) => void;
+    nodeSet: Node[];
+    onSearch?: (node: Node) => void;
     nodeColors: Map<string, string>;
 }
 
@@ -56,7 +56,7 @@ function SearchBar({
         })
         .slice(0, 3);
 
-    const handleNodeClick = (node: NodeData) => {
+    const handleNodeClick = (node: Node) => {
         if (onSearch !== undefined) {
             onSearch(node);
         }
@@ -120,7 +120,9 @@ function SearchBar({
                     >
                         <div
                             className={"searchbar-results-circle"}
-                            style={{ backgroundColor: nodeColors.get(el.type) }}
+                            style={{
+                                backgroundColor: el.type.color,
+                            }}
                         ></div>
                         <div>{el.name}</div>
                     </div>
diff --git a/src/display/display.tsx b/src/display/display.tsx
index 13ec325f2f50e42f7e93aeecb4c175cc0bc4deb8..3b5c52a833c63cda53474d25d9140b7a5bd0c412 100644
--- a/src/display/display.tsx
+++ b/src/display/display.tsx
@@ -5,7 +5,7 @@ import PropTypes, { InferType } from "prop-types";
 import "./display.css";
 import { GraphNode, GraphRenderer } from "./renderer";
 import * as Helpers from "./helpers";
-import Graph, { NodeData } from "../common/graph";
+import Graph, { Node } from "../common/graph";
 import { loadGraphJson } from "../common/datasets";
 import NodeInfoBar from "./components/nodeinfo/nodeinfobar";
 import FilterMenu from "./components/nodefilter/filtermenu";
@@ -69,11 +69,11 @@ class Display extends React.Component<
         fetchGraph();
     }
 
-    handleNodeClicked(node: NodeData) {
+    handleNodeClicked(node: Node) {
         this.setState({ currentNode: node, nodeActive: true });
     }
 
-    handleNodeChangeRequest(node: NodeData) {
+    handleNodeChangeRequest(node: Node) {
         this.rendererRef.current.focusOnNode(node as GraphNode);
         this.rendererRef.current.displayNodeSelection(node as GraphNode);
         this.handleNodeClicked(node);
@@ -145,7 +145,7 @@ class Display extends React.Component<
                 {this.state.currentNode && (
                     <NodeInfoBar
                         node={this.state.currentNode}
-                        nodeColors={this.state.graph.nodeColors}
+                        nodeColors={this.state.graph.nameToObjectGroup}
                         height={this.state.nodeActive ? this.state.height : 0}
                         onClose={() => {
                             this.handleNodeClose();
@@ -157,7 +157,7 @@ class Display extends React.Component<
 
                 {this.state.graph && (
                     <FilterMenu
-                        classes={this.graph.nodeColors}
+                        classes={this.graph.nameToObjectGroup}
                         onVisibilityChange={this.handleNodeFilter}
                     />
                 )}
diff --git a/src/display/renderer.tsx b/src/display/renderer.tsx
index a1ac0494ec01e0f002013978dc743b51b2d1367b..382e0ef3809ce7fc115220ffafe6123c8ccd91a3 100644
--- a/src/display/renderer.tsx
+++ b/src/display/renderer.tsx
@@ -10,9 +10,9 @@ import React from "react";
 import PropTypes, { InferType } from "prop-types";
 import SpriteText from "three-spritetext";
 import { Object3D, Sprite } from "three";
-import Graph, { Coordinate, LinkData, NodeData } from "../common/graph";
+import Graph, { Coordinate, Link, Node } from "../common/graph";
 
-export interface GraphNode extends NodeData {
+export interface GraphNode extends Node {
     x: number;
     y: number;
     z: number;
@@ -26,7 +26,7 @@ export interface GraphNode extends NodeData {
     __threeObj: THREE.Group;
 }
 
-export interface GraphLink extends LinkData {
+export interface GraphLink extends Link {
     __lineObj?: Line2;
 }
 
@@ -62,11 +62,15 @@ export class GraphRenderer extends React.PureComponent<
     constructor(props: InferType<typeof GraphRenderer.propTypes>) {
         super(props);
 
+        this.reset();
+        this.forceGraph = React.createRef();
+    }
+
+    reset() {
         this.highlightedNodes = new Set();
         this.highlightedLinks = new Set();
         this.node3dObjects = new Map<string, THREE.Group>();
         this.hoverNode = null;
-        this.forceGraph = React.createRef();
     }
 
     componentDidMount() {
@@ -112,7 +116,7 @@ export class GraphRenderer extends React.PureComponent<
 
         const material = new THREE.SpriteMaterial({
             //map: imageTexture,
-            color: this.props.graph.nodeColors.get(node.type),
+            color: node.type.color,
             alphaMap: imageAlpha,
             transparent: true,
             alphaTest: 0.2,
@@ -129,11 +133,11 @@ export class GraphRenderer extends React.PureComponent<
         return group;
     }
 
-    drawLink(link: LinkData) {
+    drawLink(link: Link) {
         const colors = new Float32Array(
             [].concat(
                 ...[link.target, link.source]
-                    .map((node) => this.props.graph.nodeColors.get(node.type))
+                    .map((node) => node.type.color)
                     .map((color) => color.replace(/[^\d,]/g, "").split(",")) // Extract rgb() color components
                     .map((rgb) => rgb.map((v: string) => parseInt(v) / 255))
             )
@@ -356,6 +360,7 @@ export class GraphRenderer extends React.PureComponent<
     }
 
     render() {
+        this.reset();
         return (
             <ForceGraph3D
                 ref={this.forceGraph}
@@ -365,7 +370,7 @@ export class GraphRenderer extends React.PureComponent<
                 rendererConfig={{ antialias: true }}
                 // nodeLabel={"hidden"}
                 nodeThreeObject={(node: GraphNode) => this.drawNode(node)}
-                linkThreeObject={(link: LinkData) => this.drawLink(link)}
+                linkThreeObject={(link: Link) => this.drawLink(link)}
                 onNodeClick={(node: GraphNode) => this.onNodeClick(node)}
                 onBackgroundClick={() => this.deselectNode()}
                 //d3AlphaDecay={0.1}