diff --git a/daemon/core/api/grpc/events.py b/daemon/core/api/grpc/events.py
index 172cec82..0bab096b 100644
--- a/daemon/core/api/grpc/events.py
+++ b/daemon/core/api/grpc/events.py
@@ -80,14 +80,14 @@ def handle_link_event(event: LinkData) -> core_pb2.LinkEvent:
         unidirectional=event.unidirectional,
     )
     link = core_pb2.Link(
-        type=event.link_type,
+        type=event.link_type.value,
         node_one_id=event.node1_id,
         node_two_id=event.node2_id,
         interface_one=interface_one,
         interface_two=interface_two,
         options=options,
     )
-    return core_pb2.LinkEvent(message_type=event.message_type, link=link)
+    return core_pb2.LinkEvent(message_type=event.message_type.value, link=link)
 
 
 def handle_session_event(event: EventData) -> core_pb2.SessionEvent:
@@ -102,7 +102,7 @@ def handle_session_event(event: EventData) -> core_pb2.SessionEvent:
         event_time = float(event_time)
     return core_pb2.SessionEvent(
         node_id=event.node,
-        event=event.event_type,
+        event=event.event_type.value,
         name=event.name,
         data=event.data,
         time=event_time,
@@ -158,7 +158,7 @@ def handle_file_event(event: FileData) -> core_pb2.FileEvent:
     :return: file event
     """
     return core_pb2.FileEvent(
-        message_type=event.message_type,
+        message_type=event.message_type.value,
         node_id=event.node,
         name=event.name,
         mode=event.mode,
diff --git a/daemon/core/api/grpc/grpcutils.py b/daemon/core/api/grpc/grpcutils.py
index 4ee492b9..77813b34 100644
--- a/daemon/core/api/grpc/grpcutils.py
+++ b/daemon/core/api/grpc/grpcutils.py
@@ -26,11 +26,7 @@ def add_node_data(node_proto: core_pb2.Node) -> Tuple[NodeTypes, int, NodeOption
     :return: node type, id, and options
     """
     _id = node_proto.id
-    _type = node_proto.type
-    if _type is None:
-        _type = NodeTypes.DEFAULT.value
-    _type = NodeTypes(_type)
-
+    _type = NodeTypes(node_proto.type)
     options = NodeOptions(name=node_proto.name, model=node_proto.model)
     options.icon = node_proto.icon
     options.opaque = node_proto.opaque
@@ -233,7 +229,7 @@ def get_links(session: Session, node: NodeBase):
     :return: [core.api.grpc.core_pb2.Link]
     """
     links = []
-    for link_data in node.all_link_data(0):
+    for link_data in node.all_link_data():
         link = convert_link(session, link_data)
         links.append(link)
     return links
@@ -325,7 +321,7 @@ def convert_link(session: Session, link_data: LinkData) -> core_pb2.Link:
     )
 
     return core_pb2.Link(
-        type=link_data.link_type,
+        type=link_data.link_type.value,
         node_one_id=link_data.node1_id,
         node_two_id=link_data.node2_id,
         interface_one=interface_one,
diff --git a/daemon/core/api/grpc/server.py b/daemon/core/api/grpc/server.py
index 69fc0c48..cabc0f1c 100644
--- a/daemon/core/api/grpc/server.py
+++ b/daemon/core/api/grpc/server.py
@@ -173,7 +173,8 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
 
         # add all hooks
         for hook in request.hooks:
-            session.add_hook(hook.state, hook.file, None, hook.data)
+            state = EventTypes(hook.state)
+            session.add_hook(state, hook.file, None, hook.data)
 
         # create nodes
         _, exceptions = grpcutils.create_nodes(session, request.nodes)
@@ -279,7 +280,7 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
         session.location.setrefgeo(47.57917, -122.13232, 2.0)
         session.location.refscale = 150000.0
         return core_pb2.CreateSessionResponse(
-            session_id=session.id, state=session.state
+            session_id=session.id, state=session.state.value
         )
 
     def DeleteSession(
@@ -312,7 +313,7 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
             session = self.coreemu.sessions[session_id]
             session_summary = core_pb2.SessionSummary(
                 id=session_id,
-                state=session.state,
+                state=session.state.value,
                 nodes=session.get_node_count(),
                 file=session.file_name,
             )
@@ -521,7 +522,9 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
             node_links = get_links(session, node)
             links.extend(node_links)
 
-        session_proto = core_pb2.Session(state=session.state, nodes=nodes, links=links)
+        session_proto = core_pb2.Session(
+            state=session.state.value, nodes=nodes, links=links
+        )
         return core_pb2.GetSessionResponse(session=session_proto)
 
     def AddSessionServer(
@@ -718,7 +721,7 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
             if request.source:
                 source = request.source
             if not has_geo:
-                node_data = node.data(0, source=source)
+                node_data = node.data(source=source)
                 session.broadcast_node(node_data)
         except CoreError:
             result = False
@@ -895,7 +898,7 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
         for state in session._hooks:
             state_hooks = session._hooks[state]
             for file_name, file_data in state_hooks:
-                hook = core_pb2.Hook(state=state, file=file_name, data=file_data)
+                hook = core_pb2.Hook(state=state.value, file=file_name, data=file_data)
                 hooks.append(hook)
         return core_pb2.GetHooksResponse(hooks=hooks)
 
@@ -912,7 +915,8 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
         logging.debug("add hook: %s", request)
         session = self.get_session(request.session_id, context)
         hook = request.hook
-        session.add_hook(hook.state, hook.file, None, hook.data)
+        state = EventTypes(hook.state)
+        session.add_hook(state, hook.file, None, hook.data)
         return core_pb2.AddHookResponse(result=True)
 
     def GetMobilityConfigs(
@@ -1266,7 +1270,7 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
         session.mobility.set_model_config(
             wlan_config.node_id, BasicRangeModel.name, wlan_config.config
         )
-        if session.state == EventTypes.RUNTIME_STATE.value:
+        if session.state == EventTypes.RUNTIME_STATE:
             node = self.get_node(session, wlan_config.node_id, context)
             node.updatemodel(wlan_config.config)
         return core_pb2.SetWlanConfigResponse(result=True)
@@ -1491,12 +1495,12 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
 
         if emane_one.id == emane_two.id:
             if request.linked:
-                flag = MessageFlags.ADD.value
+                flag = MessageFlags.ADD
             else:
-                flag = MessageFlags.DELETE.value
+                flag = MessageFlags.DELETE
             link = LinkData(
                 message_type=flag,
-                link_type=LinkTypes.WIRELESS.value,
+                link_type=LinkTypes.WIRELESS,
                 node1_id=node_one.id,
                 node2_id=node_two.id,
                 network_id=emane_one.id,
diff --git a/daemon/core/api/tlv/coreapi.py b/daemon/core/api/tlv/coreapi.py
index b72c186b..b8021b9f 100644
--- a/daemon/core/api/tlv/coreapi.py
+++ b/daemon/core/api/tlv/coreapi.py
@@ -13,7 +13,7 @@ from enum import Enum
 import netaddr
 
 from core.api.tlv import structutils
-from core.emulator.enumerations import (
+from core.api.tlv.enumerations import (
     ConfigTlvs,
     EventTlvs,
     ExceptionTlvs,
@@ -21,12 +21,11 @@ from core.emulator.enumerations import (
     FileTlvs,
     InterfaceTlvs,
     LinkTlvs,
-    MessageFlags,
     MessageTypes,
     NodeTlvs,
-    RegisterTlvs,
     SessionTlvs,
 )
+from core.emulator.enumerations import MessageFlags, RegisterTlvs
 
 
 class CoreTlvData:
diff --git a/daemon/core/api/tlv/corehandlers.py b/daemon/core/api/tlv/corehandlers.py
index 1f3b24e9..da2d730d 100644
--- a/daemon/core/api/tlv/corehandlers.py
+++ b/daemon/core/api/tlv/corehandlers.py
@@ -15,26 +15,28 @@ from queue import Empty, Queue
 
 from core import utils
 from core.api.tlv import coreapi, dataconversion, structutils
-from core.config import ConfigShim
-from core.emulator.data import ConfigData, EventData, ExceptionData, FileData
-from core.emulator.emudata import InterfaceData, LinkOptions, NodeOptions
-from core.emulator.enumerations import (
-    ConfigDataTypes,
+from core.api.tlv.dataconversion import ConfigShim
+from core.api.tlv.enumerations import (
     ConfigFlags,
     ConfigTlvs,
     EventTlvs,
-    EventTypes,
     ExceptionTlvs,
     ExecuteTlvs,
     FileTlvs,
     LinkTlvs,
-    LinkTypes,
-    MessageFlags,
     MessageTypes,
     NodeTlvs,
+    SessionTlvs,
+)
+from core.emulator.data import ConfigData, EventData, ExceptionData, FileData
+from core.emulator.emudata import InterfaceData, LinkOptions, NodeOptions
+from core.emulator.enumerations import (
+    ConfigDataTypes,
+    EventTypes,
+    LinkTypes,
+    MessageFlags,
     NodeTypes,
     RegisterTlvs,
-    SessionTlvs,
 )
 from core.errors import CoreCommandError, CoreError
 from core.location.mobility import BasicRangeModel
@@ -228,7 +230,7 @@ class CoreHandler(socketserver.BaseRequestHandler):
             coreapi.CoreEventTlv,
             [
                 (EventTlvs.NODE, event_data.node),
-                (EventTlvs.TYPE, event_data.event_type),
+                (EventTlvs.TYPE, event_data.event_type.value),
                 (EventTlvs.NAME, event_data.name),
                 (EventTlvs.DATA, event_data.data),
                 (EventTlvs.TIME, event_data.time),
@@ -265,7 +267,7 @@ class CoreHandler(socketserver.BaseRequestHandler):
                 (FileTlvs.COMPRESSED_DATA, file_data.compressed_data),
             ],
         )
-        message = coreapi.CoreFileMessage.pack(file_data.message_type, tlv_data)
+        message = coreapi.CoreFileMessage.pack(file_data.message_type.value, tlv_data)
 
         try:
             self.sendall(message)
@@ -356,7 +358,7 @@ class CoreHandler(socketserver.BaseRequestHandler):
                 (LinkTlvs.BURST, link_data.burst),
                 (LinkTlvs.SESSION, link_data.session),
                 (LinkTlvs.MBURST, link_data.mburst),
-                (LinkTlvs.TYPE, link_data.link_type),
+                (LinkTlvs.TYPE, link_data.link_type.value),
                 (LinkTlvs.GUI_ATTRIBUTES, link_data.gui_attributes),
                 (LinkTlvs.UNIDIRECTIONAL, link_data.unidirectional),
                 (LinkTlvs.EMULATION_ID, link_data.emulation_id),
@@ -380,7 +382,7 @@ class CoreHandler(socketserver.BaseRequestHandler):
             ],
         )
 
-        message = coreapi.CoreLinkMessage.pack(link_data.message_type, tlv_data)
+        message = coreapi.CoreLinkMessage.pack(link_data.message_type.value, tlv_data)
 
         try:
             self.sendall(message)
@@ -396,7 +398,6 @@ class CoreHandler(socketserver.BaseRequestHandler):
         logging.info(
             "GUI has connected to session %d at %s", self.session.id, time.ctime()
         )
-
         tlv_data = b""
         tlv_data += coreapi.CoreRegisterTlv.pack(
             RegisterTlvs.EXECUTE_SERVER.value, "core-daemon"
@@ -406,29 +407,29 @@ class CoreHandler(socketserver.BaseRequestHandler):
         )
         tlv_data += coreapi.CoreRegisterTlv.pack(RegisterTlvs.UTILITY.value, "broker")
         tlv_data += coreapi.CoreRegisterTlv.pack(
-            self.session.location.config_type, self.session.location.name
+            self.session.location.config_type.value, self.session.location.name
         )
         tlv_data += coreapi.CoreRegisterTlv.pack(
-            self.session.mobility.config_type, self.session.mobility.name
+            self.session.mobility.config_type.value, self.session.mobility.name
         )
         for model_name in self.session.mobility.models:
             model_class = self.session.mobility.models[model_name]
             tlv_data += coreapi.CoreRegisterTlv.pack(
-                model_class.config_type, model_class.name
+                model_class.config_type.value, model_class.name
             )
         tlv_data += coreapi.CoreRegisterTlv.pack(
-            self.session.services.config_type, self.session.services.name
+            self.session.services.config_type.value, self.session.services.name
         )
         tlv_data += coreapi.CoreRegisterTlv.pack(
-            self.session.emane.config_type, self.session.emane.name
+            self.session.emane.config_type.value, self.session.emane.name
         )
         for model_name in self.session.emane.models:
             model_class = self.session.emane.models[model_name]
             tlv_data += coreapi.CoreRegisterTlv.pack(
-                model_class.config_type, model_class.name
+                model_class.config_type.value, model_class.name
             )
         tlv_data += coreapi.CoreRegisterTlv.pack(
-            self.session.options.config_type, self.session.options.name
+            self.session.options.config_type.value, self.session.options.name
         )
         tlv_data += coreapi.CoreRegisterTlv.pack(RegisterTlvs.UTILITY.value, "metadata")
 
@@ -723,7 +724,7 @@ class CoreHandler(socketserver.BaseRequestHandler):
                 if message.flags & MessageFlags.STRING.value:
                     self.node_status_request[node.id] = True
 
-                if self.session.state == EventTypes.RUNTIME_STATE.value:
+                if self.session.state == EventTypes.RUNTIME_STATE:
                     self.send_node_emulation_id(node.id)
         elif message.flags & MessageFlags.DELETE.value:
             with self._shutdown_lock:
@@ -966,7 +967,7 @@ class CoreHandler(socketserver.BaseRequestHandler):
                     retries = 10
                     # wait for session to enter RUNTIME state, to prevent GUI from
                     # connecting while nodes are still being instantiated
-                    while session.state != EventTypes.RUNTIME_STATE.value:
+                    while session.state != EventTypes.RUNTIME_STATE:
                         logging.debug(
                             "waiting for session %d to enter RUNTIME state", sid
                         )
@@ -1375,7 +1376,7 @@ class CoreHandler(socketserver.BaseRequestHandler):
                 parsed_config = ConfigShim.str_to_dict(values_str)
 
             self.session.mobility.set_model_config(node_id, object_name, parsed_config)
-            if self.session.state == EventTypes.RUNTIME_STATE.value and parsed_config:
+            if self.session.state == EventTypes.RUNTIME_STATE and parsed_config:
                 try:
                     node = self.session.get_node(node_id)
                     if object_name == BasicRangeModel.name:
@@ -1502,6 +1503,7 @@ class CoreHandler(socketserver.BaseRequestHandler):
                         logging.error("error setting hook having state '%s'", state)
                         return ()
                     state = int(state)
+                    state = EventTypes(state)
                     self.session.add_hook(state, file_name, source_name, data)
                     return ()
 
@@ -1538,9 +1540,11 @@ class CoreHandler(socketserver.BaseRequestHandler):
         :return: reply messages
         :raises core.CoreError: when event type <= SHUTDOWN_STATE and not a known node id
         """
+        event_type_value = message.get_tlv(EventTlvs.TYPE.value)
+        event_type = EventTypes(event_type_value)
         event_data = EventData(
             node=message.get_tlv(EventTlvs.NODE.value),
-            event_type=message.get_tlv(EventTlvs.TYPE.value),
+            event_type=event_type,
             name=message.get_tlv(EventTlvs.NAME.value),
             data=message.get_tlv(EventTlvs.DATA.value),
             time=message.get_tlv(EventTlvs.TIME.value),
@@ -1549,7 +1553,6 @@ class CoreHandler(socketserver.BaseRequestHandler):
 
         if event_data.event_type is None:
             raise NotImplementedError("Event message missing event type")
-        event_type = EventTypes(event_data.event_type)
         node_id = event_data.node
 
         logging.debug("handling event %s at %s", event_type.name, time.ctime())
@@ -1667,25 +1670,19 @@ class CoreHandler(socketserver.BaseRequestHandler):
                 unknown.append(service_name)
                 continue
 
-            if (
-                event_type == EventTypes.STOP.value
-                or event_type == EventTypes.RESTART.value
-            ):
+            if event_type in [EventTypes.STOP, EventTypes.RESTART]:
                 status = self.session.services.stop_service(node, service)
                 if status:
                     fail += f"Stop {service.name},"
-            if (
-                event_type == EventTypes.START.value
-                or event_type == EventTypes.RESTART.value
-            ):
+            if event_type in [EventTypes.START, EventTypes.RESTART]:
                 status = self.session.services.startup_service(node, service)
                 if status:
                     fail += f"Start ({service.name}),"
-            if event_type == EventTypes.PAUSE.value:
+            if event_type == EventTypes.PAUSE:
                 status = self.session.services.validate_service(node, service)
                 if status:
                     fail += f"{service.name},"
-            if event_type == EventTypes.RECONFIGURE.value:
+            if event_type == EventTypes.RECONFIGURE:
                 self.session.services.service_reconfigure(node, service)
 
         fail_data = ""
@@ -1845,11 +1842,11 @@ class CoreHandler(socketserver.BaseRequestHandler):
         with self.session._nodes_lock:
             for node_id in self.session.nodes:
                 node = self.session.nodes[node_id]
-                node_data = node.data(message_type=MessageFlags.ADD.value)
+                node_data = node.data(message_type=MessageFlags.ADD)
                 if node_data:
                     nodes_data.append(node_data)
 
-                node_links = node.all_link_data(flags=MessageFlags.ADD.value)
+                node_links = node.all_link_data(flags=MessageFlags.ADD)
                 for link_data in node_links:
                     links_data.append(link_data)
 
@@ -1917,7 +1914,7 @@ class CoreHandler(socketserver.BaseRequestHandler):
 
             for file_name, config_data in self.session.services.all_files(service):
                 file_data = FileData(
-                    message_type=MessageFlags.ADD.value,
+                    message_type=MessageFlags.ADD,
                     node=node_id,
                     name=str(file_name),
                     type=opaque,
@@ -1931,7 +1928,7 @@ class CoreHandler(socketserver.BaseRequestHandler):
         for state in sorted(self.session._hooks.keys()):
             for file_name, config_data in self.session._hooks[state]:
                 file_data = FileData(
-                    message_type=MessageFlags.ADD.value,
+                    message_type=MessageFlags.ADD,
                     name=str(file_name),
                     type=f"hook:{state}",
                     data=str(config_data),
@@ -2052,7 +2049,7 @@ class CoreUdpHandler(CoreHandler):
                 current_session = self.server.mainserver.coreemu.sessions[session_id]
                 current_node_count = current_session.get_node_count()
                 if (
-                    current_session.state == EventTypes.RUNTIME_STATE.value
+                    current_session.state == EventTypes.RUNTIME_STATE
                     and current_node_count > node_count
                 ):
                     node_count = current_node_count
diff --git a/daemon/core/api/tlv/dataconversion.py b/daemon/core/api/tlv/dataconversion.py
index 8d47613d..21730afb 100644
--- a/daemon/core/api/tlv/dataconversion.py
+++ b/daemon/core/api/tlv/dataconversion.py
@@ -1,9 +1,14 @@
 """
 Converts CORE data objects into legacy API messages.
 """
+import logging
+from collections import OrderedDict
+from typing import Dict, List
 
 from core.api.tlv import coreapi, structutils
-from core.emulator.enumerations import ConfigTlvs, NodeTlvs
+from core.api.tlv.enumerations import ConfigTlvs, NodeTlvs
+from core.config import ConfigGroup, ConfigurableOptions
+from core.emulator.data import ConfigData
 
 
 def convert_node(node_data):
@@ -17,7 +22,7 @@ def convert_node(node_data):
         coreapi.CoreNodeTlv,
         [
             (NodeTlvs.NUMBER, node_data.id),
-            (NodeTlvs.TYPE, node_data.node_type),
+            (NodeTlvs.TYPE, node_data.node_type.value),
             (NodeTlvs.NAME, node_data.name),
             (NodeTlvs.IP_ADDRESS, node_data.ip_address),
             (NodeTlvs.MAC_ADDRESS, node_data.mac_address),
@@ -38,7 +43,7 @@ def convert_node(node_data):
             (NodeTlvs.OPAQUE, node_data.opaque),
         ],
     )
-    return coreapi.CoreNodeMessage.pack(node_data.message_type, tlv_data)
+    return coreapi.CoreNodeMessage.pack(node_data.message_type.value, tlv_data)
 
 
 def convert_config(config_data):
@@ -67,3 +72,102 @@ def convert_config(config_data):
         ],
     )
     return coreapi.CoreConfMessage.pack(config_data.message_type, tlv_data)
+
+
+class ConfigShim:
+    """
+    Provides helper methods for converting newer configuration values into TLV
+    compatible formats.
+    """
+
+    @classmethod
+    def str_to_dict(cls, key_values: str) -> Dict[str, str]:
+        """
+        Converts a TLV key/value string into an ordered mapping.
+
+        :param key_values:
+        :return: ordered mapping of key/value pairs
+        """
+        key_values = key_values.split("|")
+        values = OrderedDict()
+        for key_value in key_values:
+            key, value = key_value.split("=", 1)
+            values[key] = value
+        return values
+
+    @classmethod
+    def groups_to_str(cls, config_groups: List[ConfigGroup]) -> str:
+        """
+        Converts configuration groups to a TLV formatted string.
+
+        :param config_groups: configuration groups to format
+        :return: TLV configuration group string
+        """
+        group_strings = []
+        for config_group in config_groups:
+            group_string = (
+                f"{config_group.name}:{config_group.start}-{config_group.stop}"
+            )
+            group_strings.append(group_string)
+        return "|".join(group_strings)
+
+    @classmethod
+    def config_data(
+        cls,
+        flags: int,
+        node_id: int,
+        type_flags: int,
+        configurable_options: ConfigurableOptions,
+        config: Dict[str, str],
+    ) -> ConfigData:
+        """
+        Convert this class to a Config API message. Some TLVs are defined
+        by the class, but node number, conf type flags, and values must
+        be passed in.
+
+        :param flags: message flags
+        :param node_id: node id
+        :param type_flags: type flags
+        :param configurable_options: options to create config data for
+        :param config: configuration values for options
+        :return: configuration data object
+        """
+        key_values = None
+        captions = None
+        data_types = []
+        possible_values = []
+        logging.debug("configurable: %s", configurable_options)
+        logging.debug("configuration options: %s", configurable_options.configurations)
+        logging.debug("configuration data: %s", config)
+        for configuration in configurable_options.configurations():
+            if not captions:
+                captions = configuration.label
+            else:
+                captions += f"|{configuration.label}"
+
+            data_types.append(configuration.type.value)
+
+            options = ",".join(configuration.options)
+            possible_values.append(options)
+
+            _id = configuration.id
+            config_value = config.get(_id, configuration.default)
+            key_value = f"{_id}={config_value}"
+            if not key_values:
+                key_values = key_value
+            else:
+                key_values += f"|{key_value}"
+
+        groups_str = cls.groups_to_str(configurable_options.config_groups())
+        return ConfigData(
+            message_type=flags,
+            node=node_id,
+            object=configurable_options.name,
+            type=type_flags,
+            data_types=tuple(data_types),
+            data_values=key_values,
+            captions=captions,
+            possible_values="|".join(possible_values),
+            bitmap=configurable_options.bitmap,
+            groups=groups_str,
+        )
diff --git a/daemon/core/api/tlv/enumerations.py b/daemon/core/api/tlv/enumerations.py
new file mode 100644
index 00000000..ed06bbe7
--- /dev/null
+++ b/daemon/core/api/tlv/enumerations.py
@@ -0,0 +1,212 @@
+"""
+Enumerations specific to the CORE TLV API.
+"""
+from enum import Enum
+
+CORE_API_PORT = 4038
+
+
+class MessageTypes(Enum):
+    """
+    CORE message types.
+    """
+
+    NODE = 0x01
+    LINK = 0x02
+    EXECUTE = 0x03
+    REGISTER = 0x04
+    CONFIG = 0x05
+    FILE = 0x06
+    INTERFACE = 0x07
+    EVENT = 0x08
+    SESSION = 0x09
+    EXCEPTION = 0x0A
+
+
+class NodeTlvs(Enum):
+    """
+    Node type, length, value enumerations.
+    """
+
+    NUMBER = 0x01
+    TYPE = 0x02
+    NAME = 0x03
+    IP_ADDRESS = 0x04
+    MAC_ADDRESS = 0x05
+    IP6_ADDRESS = 0x06
+    MODEL = 0x07
+    EMULATION_SERVER = 0x08
+    SESSION = 0x0A
+    X_POSITION = 0x20
+    Y_POSITION = 0x21
+    CANVAS = 0x22
+    EMULATION_ID = 0x23
+    NETWORK_ID = 0x24
+    SERVICES = 0x25
+    LATITUDE = 0x30
+    LONGITUDE = 0x31
+    ALTITUDE = 0x32
+    ICON = 0x42
+    OPAQUE = 0x50
+
+
+class LinkTlvs(Enum):
+    """
+    Link type, length, value enumerations.
+    """
+
+    N1_NUMBER = 0x01
+    N2_NUMBER = 0x02
+    DELAY = 0x03
+    BANDWIDTH = 0x04
+    PER = 0x05
+    DUP = 0x06
+    JITTER = 0x07
+    MER = 0x08
+    BURST = 0x09
+    SESSION = 0x0A
+    MBURST = 0x10
+    TYPE = 0x20
+    GUI_ATTRIBUTES = 0x21
+    UNIDIRECTIONAL = 0x22
+    EMULATION_ID = 0x23
+    NETWORK_ID = 0x24
+    KEY = 0x25
+    INTERFACE1_NUMBER = 0x30
+    INTERFACE1_IP4 = 0x31
+    INTERFACE1_IP4_MASK = 0x32
+    INTERFACE1_MAC = 0x33
+    INTERFACE1_IP6 = 0x34
+    INTERFACE1_IP6_MASK = 0x35
+    INTERFACE2_NUMBER = 0x36
+    INTERFACE2_IP4 = 0x37
+    INTERFACE2_IP4_MASK = 0x38
+    INTERFACE2_MAC = 0x39
+    INTERFACE2_IP6 = 0x40
+    INTERFACE2_IP6_MASK = 0x41
+    INTERFACE1_NAME = 0x42
+    INTERFACE2_NAME = 0x43
+    OPAQUE = 0x50
+
+
+class ExecuteTlvs(Enum):
+    """
+    Execute type, length, value enumerations.
+    """
+
+    NODE = 0x01
+    NUMBER = 0x02
+    TIME = 0x03
+    COMMAND = 0x04
+    RESULT = 0x05
+    STATUS = 0x06
+    SESSION = 0x0A
+
+
+class ConfigTlvs(Enum):
+    """
+    Configuration type, length, value enumerations.
+    """
+
+    NODE = 0x01
+    OBJECT = 0x02
+    TYPE = 0x03
+    DATA_TYPES = 0x04
+    VALUES = 0x05
+    CAPTIONS = 0x06
+    BITMAP = 0x07
+    POSSIBLE_VALUES = 0x08
+    GROUPS = 0x09
+    SESSION = 0x0A
+    INTERFACE_NUMBER = 0x0B
+    NETWORK_ID = 0x24
+    OPAQUE = 0x50
+
+
+class ConfigFlags(Enum):
+    """
+    Configuration flags.
+    """
+
+    NONE = 0x00
+    REQUEST = 0x01
+    UPDATE = 0x02
+    RESET = 0x03
+
+
+class FileTlvs(Enum):
+    """
+    File type, length, value enumerations.
+    """
+
+    NODE = 0x01
+    NAME = 0x02
+    MODE = 0x03
+    NUMBER = 0x04
+    TYPE = 0x05
+    SOURCE_NAME = 0x06
+    SESSION = 0x0A
+    DATA = 0x10
+    COMPRESSED_DATA = 0x11
+
+
+class InterfaceTlvs(Enum):
+    """
+    Interface type, length, value enumerations.
+    """
+
+    NODE = 0x01
+    NUMBER = 0x02
+    NAME = 0x03
+    IP_ADDRESS = 0x04
+    MASK = 0x05
+    MAC_ADDRESS = 0x06
+    IP6_ADDRESS = 0x07
+    IP6_MASK = 0x08
+    TYPE = 0x09
+    SESSION = 0x0A
+    STATE = 0x0B
+    EMULATION_ID = 0x23
+    NETWORK_ID = 0x24
+
+
+class EventTlvs(Enum):
+    """
+    Event type, length, value enumerations.
+    """
+
+    NODE = 0x01
+    TYPE = 0x02
+    NAME = 0x03
+    DATA = 0x04
+    TIME = 0x05
+    SESSION = 0x0A
+
+
+class SessionTlvs(Enum):
+    """
+    Session type, length, value enumerations.
+    """
+
+    NUMBER = 0x01
+    NAME = 0x02
+    FILE = 0x03
+    NODE_COUNT = 0x04
+    DATE = 0x05
+    THUMB = 0x06
+    USER = 0x07
+    OPAQUE = 0x0A
+
+
+class ExceptionTlvs(Enum):
+    """
+    Exception type, length, value enumerations.
+    """
+
+    NODE = 0x01
+    SESSION = 0x02
+    LEVEL = 0x03
+    SOURCE = 0x04
+    DATE = 0x05
+    TEXT = 0x06
+    OPAQUE = 0x0A
diff --git a/daemon/core/config.py b/daemon/core/config.py
index b7c20362..1f5bc3c0 100644
--- a/daemon/core/config.py
+++ b/daemon/core/config.py
@@ -7,7 +7,6 @@ from collections import OrderedDict
 from typing import TYPE_CHECKING, Dict, List, Tuple, Type, Union
 
 from core.emane.nodes import EmaneNet
-from core.emulator.data import ConfigData
 from core.emulator.enumerations import ConfigDataTypes
 from core.nodes.network import WlanNode
 
@@ -110,104 +109,6 @@ class ConfigurableOptions:
         )
 
 
-class ConfigShim:
-    """
-    Provides helper methods for converting newer configuration values into TLV compatible formats.
-    """
-
-    @classmethod
-    def str_to_dict(cls, key_values: str) -> Dict[str, str]:
-        """
-        Converts a TLV key/value string into an ordered mapping.
-
-        :param key_values:
-        :return: ordered mapping of key/value pairs
-        """
-        key_values = key_values.split("|")
-        values = OrderedDict()
-        for key_value in key_values:
-            key, value = key_value.split("=", 1)
-            values[key] = value
-        return values
-
-    @classmethod
-    def groups_to_str(cls, config_groups: List[ConfigGroup]) -> str:
-        """
-        Converts configuration groups to a TLV formatted string.
-
-        :param config_groups: configuration groups to format
-        :return: TLV configuration group string
-        """
-        group_strings = []
-        for config_group in config_groups:
-            group_string = (
-                f"{config_group.name}:{config_group.start}-{config_group.stop}"
-            )
-            group_strings.append(group_string)
-        return "|".join(group_strings)
-
-    @classmethod
-    def config_data(
-        cls,
-        flags: int,
-        node_id: int,
-        type_flags: int,
-        configurable_options: ConfigurableOptions,
-        config: Dict[str, str],
-    ) -> ConfigData:
-        """
-        Convert this class to a Config API message. Some TLVs are defined
-        by the class, but node number, conf type flags, and values must
-        be passed in.
-
-        :param flags: message flags
-        :param node_id: node id
-        :param type_flags: type flags
-        :param configurable_options: options to create config data for
-        :param config: configuration values for options
-        :return: configuration data object
-        """
-        key_values = None
-        captions = None
-        data_types = []
-        possible_values = []
-        logging.debug("configurable: %s", configurable_options)
-        logging.debug("configuration options: %s", configurable_options.configurations)
-        logging.debug("configuration data: %s", config)
-        for configuration in configurable_options.configurations():
-            if not captions:
-                captions = configuration.label
-            else:
-                captions += f"|{configuration.label}"
-
-            data_types.append(configuration.type.value)
-
-            options = ",".join(configuration.options)
-            possible_values.append(options)
-
-            _id = configuration.id
-            config_value = config.get(_id, configuration.default)
-            key_value = f"{_id}={config_value}"
-            if not key_values:
-                key_values = key_value
-            else:
-                key_values += f"|{key_value}"
-
-        groups_str = cls.groups_to_str(configurable_options.config_groups())
-        return ConfigData(
-            message_type=flags,
-            node=node_id,
-            object=configurable_options.name,
-            type=type_flags,
-            data_types=tuple(data_types),
-            data_values=key_values,
-            captions=captions,
-            possible_values="|".join(possible_values),
-            bitmap=configurable_options.bitmap,
-            groups=groups_str,
-        )
-
-
 class ConfigurableManager:
     """
     Provides convenience methods for storing and retrieving configuration options for
diff --git a/daemon/core/emane/emanemanager.py b/daemon/core/emane/emanemanager.py
index ea4a019d..37185c93 100644
--- a/daemon/core/emane/emanemanager.py
+++ b/daemon/core/emane/emanemanager.py
@@ -60,7 +60,7 @@ class EmaneManager(ModelManager):
     """
 
     name = "emane"
-    config_type = RegisterTlvs.EMULATION_SERVER.value
+    config_type = RegisterTlvs.EMULATION_SERVER
     SUCCESS, NOT_NEEDED, NOT_READY = (0, 1, 2)
     EVENTCFGVAR = "LIBEMANEEVENTSERVICECONFIG"
     DEFAULT_LOG_LEVEL = 3
@@ -806,7 +806,7 @@ class EmaneManager(ModelManager):
         # don"t use node.setposition(x,y,z) which generates an event
         node.position.set(x, y, z)
         node.position.set_geo(lon, lat, alt)
-        node_data = node.data(message_type=0, lat=lat, lon=lon, alt=alt)
+        node_data = node.data(lat=lat, lon=lon, alt=alt)
         self.session.broadcast_node(node_data)
         return True
 
diff --git a/daemon/core/emane/nodes.py b/daemon/core/emane/nodes.py
index b44d16b6..d8984f7c 100644
--- a/daemon/core/emane/nodes.py
+++ b/daemon/core/emane/nodes.py
@@ -33,8 +33,8 @@ class EmaneNet(CoreNetworkBase):
     Emane controller object that exists in a session.
     """
 
-    apitype = NodeTypes.EMANE.value
-    linktype = LinkTypes.WIRED.value
+    apitype = NodeTypes.EMANE
+    linktype = LinkTypes.WIRED
     type = "wlan"
     is_emane = True
 
@@ -103,12 +103,12 @@ class EmaneNet(CoreNetworkBase):
         set the EmaneModel associated with this node
         """
         logging.info("adding model: %s", model.name)
-        if model.config_type == RegisterTlvs.WIRELESS.value:
+        if model.config_type == RegisterTlvs.WIRELESS:
             # EmaneModel really uses values from ConfigurableManager
             #  when buildnemxml() is called, not during init()
             self.model = model(session=self.session, _id=self.id)
             self.model.update_config(config)
-        elif model.config_type == RegisterTlvs.MOBILITY.value:
+        elif model.config_type == RegisterTlvs.MOBILITY:
             self.mobility = model(session=self.session, _id=self.id)
             self.mobility.update_config(config)
 
diff --git a/daemon/core/emulator/enumerations.py b/daemon/core/emulator/enumerations.py
index f426774e..2c6e14db 100644
--- a/daemon/core/emulator/enumerations.py
+++ b/daemon/core/emulator/enumerations.py
@@ -1,35 +1,16 @@
 """
-Contains all legacy enumerations for interacting with legacy CORE code.
+Common enumerations used within CORE.
 """
 
 from enum import Enum
 
-CORE_API_VERSION = "1.23"
-CORE_API_PORT = 4038
-
-
-class MessageTypes(Enum):
-    """
-    CORE message types.
-    """
-
-    NODE = 0x01
-    LINK = 0x02
-    EXECUTE = 0x03
-    REGISTER = 0x04
-    CONFIG = 0x05
-    FILE = 0x06
-    INTERFACE = 0x07
-    EVENT = 0x08
-    SESSION = 0x09
-    EXCEPTION = 0x0A
-
 
 class MessageFlags(Enum):
     """
     CORE message flags.
     """
 
+    NONE = 0x00
     ADD = 0x01
     DELETE = 0x02
     CRI = 0x04
@@ -39,33 +20,6 @@ class MessageFlags(Enum):
     TTY = 0x40
 
 
-class NodeTlvs(Enum):
-    """
-    Node type, length, value enumerations.
-    """
-
-    NUMBER = 0x01
-    TYPE = 0x02
-    NAME = 0x03
-    IP_ADDRESS = 0x04
-    MAC_ADDRESS = 0x05
-    IP6_ADDRESS = 0x06
-    MODEL = 0x07
-    EMULATION_SERVER = 0x08
-    SESSION = 0x0A
-    X_POSITION = 0x20
-    Y_POSITION = 0x21
-    CANVAS = 0x22
-    EMULATION_ID = 0x23
-    NETWORK_ID = 0x24
-    SERVICES = 0x25
-    LATITUDE = 0x30
-    LONGITUDE = 0x31
-    ALTITUDE = 0x32
-    ICON = 0x42
-    OPAQUE = 0x50
-
-
 class NodeTypes(Enum):
     """
     Node types.
@@ -86,56 +40,6 @@ class NodeTypes(Enum):
     LXC = 16
 
 
-class Rj45Models(Enum):
-    """
-    RJ45 model types.
-    """
-
-    LINKED = 0
-    WIRELESS = 1
-    INSTALLED = 2
-
-
-# Link Message TLV Types
-class LinkTlvs(Enum):
-    """
-    Link type, length, value enumerations.
-    """
-
-    N1_NUMBER = 0x01
-    N2_NUMBER = 0x02
-    DELAY = 0x03
-    BANDWIDTH = 0x04
-    PER = 0x05
-    DUP = 0x06
-    JITTER = 0x07
-    MER = 0x08
-    BURST = 0x09
-    SESSION = 0x0A
-    MBURST = 0x10
-    TYPE = 0x20
-    GUI_ATTRIBUTES = 0x21
-    UNIDIRECTIONAL = 0x22
-    EMULATION_ID = 0x23
-    NETWORK_ID = 0x24
-    KEY = 0x25
-    INTERFACE1_NUMBER = 0x30
-    INTERFACE1_IP4 = 0x31
-    INTERFACE1_IP4_MASK = 0x32
-    INTERFACE1_MAC = 0x33
-    INTERFACE1_IP6 = 0x34
-    INTERFACE1_IP6_MASK = 0x35
-    INTERFACE2_NUMBER = 0x36
-    INTERFACE2_IP4 = 0x37
-    INTERFACE2_IP4_MASK = 0x38
-    INTERFACE2_MAC = 0x39
-    INTERFACE2_IP6 = 0x40
-    INTERFACE2_IP6_MASK = 0x41
-    INTERFACE1_NAME = 0x42
-    INTERFACE2_NAME = 0x43
-    OPAQUE = 0x50
-
-
 class LinkTypes(Enum):
     """
     Link types.
@@ -145,20 +49,6 @@ class LinkTypes(Enum):
     WIRED = 1
 
 
-class ExecuteTlvs(Enum):
-    """
-    Execute type, length, value enumerations.
-    """
-
-    NODE = 0x01
-    NUMBER = 0x02
-    TIME = 0x03
-    COMMAND = 0x04
-    RESULT = 0x05
-    STATUS = 0x06
-    SESSION = 0x0A
-
-
 class RegisterTlvs(Enum):
     """
     Register type, length, value enumerations.
@@ -173,37 +63,6 @@ class RegisterTlvs(Enum):
     SESSION = 0x0A
 
 
-class ConfigTlvs(Enum):
-    """
-    Configuration type, length, value enumerations.
-    """
-
-    NODE = 0x01
-    OBJECT = 0x02
-    TYPE = 0x03
-    DATA_TYPES = 0x04
-    VALUES = 0x05
-    CAPTIONS = 0x06
-    BITMAP = 0x07
-    POSSIBLE_VALUES = 0x08
-    GROUPS = 0x09
-    SESSION = 0x0A
-    INTERFACE_NUMBER = 0x0B
-    NETWORK_ID = 0x24
-    OPAQUE = 0x50
-
-
-class ConfigFlags(Enum):
-    """
-    Configuration flags.
-    """
-
-    NONE = 0x00
-    REQUEST = 0x01
-    UPDATE = 0x02
-    RESET = 0x03
-
-
 class ConfigDataTypes(Enum):
     """
     Configuration data types.
@@ -222,55 +81,6 @@ class ConfigDataTypes(Enum):
     BOOL = 0x0B
 
 
-class FileTlvs(Enum):
-    """
-    File type, length, value enumerations.
-    """
-
-    NODE = 0x01
-    NAME = 0x02
-    MODE = 0x03
-    NUMBER = 0x04
-    TYPE = 0x05
-    SOURCE_NAME = 0x06
-    SESSION = 0x0A
-    DATA = 0x10
-    COMPRESSED_DATA = 0x11
-
-
-class InterfaceTlvs(Enum):
-    """
-    Interface type, length, value enumerations.
-    """
-
-    NODE = 0x01
-    NUMBER = 0x02
-    NAME = 0x03
-    IP_ADDRESS = 0x04
-    MASK = 0x05
-    MAC_ADDRESS = 0x06
-    IP6_ADDRESS = 0x07
-    IP6_MASK = 0x08
-    TYPE = 0x09
-    SESSION = 0x0A
-    STATE = 0x0B
-    EMULATION_ID = 0x23
-    NETWORK_ID = 0x24
-
-
-class EventTlvs(Enum):
-    """
-    Event type, length, value enumerations.
-    """
-
-    NODE = 0x01
-    TYPE = 0x02
-    NAME = 0x03
-    DATA = 0x04
-    TIME = 0x05
-    SESSION = 0x0A
-
-
 class EventTypes(Enum):
     """
     Event types.
@@ -293,34 +103,8 @@ class EventTypes(Enum):
     RECONFIGURE = 14
     INSTANTIATION_COMPLETE = 15
 
-
-class SessionTlvs(Enum):
-    """
-    Session type, length, value enumerations.
-    """
-
-    NUMBER = 0x01
-    NAME = 0x02
-    FILE = 0x03
-    NODE_COUNT = 0x04
-    DATE = 0x05
-    THUMB = 0x06
-    USER = 0x07
-    OPAQUE = 0x0A
-
-
-class ExceptionTlvs(Enum):
-    """
-    Exception type, length, value enumerations.
-    """
-
-    NODE = 0x01
-    SESSION = 0x02
-    LEVEL = 0x03
-    SOURCE = 0x04
-    DATE = 0x05
-    TEXT = 0x06
-    OPAQUE = 0x0A
+    def should_start(self) -> bool:
+        return self.value > self.DEFINITION_STATE.value
 
 
 class ExceptionLevels(Enum):
diff --git a/daemon/core/emulator/session.py b/daemon/core/emulator/session.py
index 3a02412f..8bc10826 100644
--- a/daemon/core/emulator/session.py
+++ b/daemon/core/emulator/session.py
@@ -112,8 +112,7 @@ class Session:
         self.nodes = {}
         self._nodes_lock = threading.Lock()
 
-        # TODO: should the default state be definition?
-        self.state = EventTypes.NONE.value
+        self.state = EventTypes.DEFINITION_STATE
         self._state_time = time.monotonic()
         self._state_file = os.path.join(self.session_dir, "state")
 
@@ -121,7 +120,7 @@ class Session:
         self._hooks = {}
         self._state_hooks = {}
         self.add_state_hook(
-            state=EventTypes.RUNTIME_STATE.value, hook=self.runtime_state_hook
+            state=EventTypes.RUNTIME_STATE, hook=self.runtime_state_hook
         )
 
         # handlers for broadcasting information
@@ -345,7 +344,7 @@ class Session:
                         node_one.name,
                         node_two.name,
                     )
-                    start = self.state > EventTypes.DEFINITION_STATE.value
+                    start = self.state.should_start()
                     net_one = self.create_node(cls=PtpNet, start=start)
 
                 # node to network
@@ -578,7 +577,7 @@ class Session:
 
         try:
             # wireless link
-            if link_options.type == LinkTypes.WIRELESS.value:
+            if link_options.type == LinkTypes.WIRELESS:
                 raise CoreError("cannot update wireless link")
             else:
                 if not node_one and not node_two:
@@ -680,7 +679,7 @@ class Session:
             node_class = _cls
 
         # set node start based on current session state, override and check when rj45
-        start = self.state > EventTypes.DEFINITION_STATE.value
+        start = self.state.should_start()
         enable_rj45 = self.options.get_config("enablerj45") == "1"
         if _type == NodeTypes.RJ45 and not enable_rj45:
             start = False
@@ -755,7 +754,7 @@ class Session:
 
         # boot nodes after runtime, CoreNodes, Physical, and RJ45 are all nodes
         is_boot_node = isinstance(node, CoreNodeBase) and not isinstance(node, Rj45Node)
-        if self.state == EventTypes.RUNTIME_STATE.value and is_boot_node:
+        if self.state == EventTypes.RUNTIME_STATE and is_boot_node:
             self.write_nodes()
             self.add_remove_control_interface(node=node, remove=False)
             self.services.boot_services(node)
@@ -851,10 +850,7 @@ class Session:
 
         :return: True if active, False otherwise
         """
-        result = self.state in {
-            EventTypes.RUNTIME_STATE.value,
-            EventTypes.DATACOLLECT_STATE.value,
-        }
+        result = self.state in {EventTypes.RUNTIME_STATE, EventTypes.DATACOLLECT_STATE}
         logging.info("session(%s) checking if active: %s", self.id, result)
         return result
 
@@ -895,7 +891,9 @@ class Session:
         """
         CoreXmlWriter(self).write(file_name)
 
-    def add_hook(self, state: int, file_name: str, source_name: str, data: str) -> None:
+    def add_hook(
+        self, state: EventTypes, file_name: str, source_name: str, data: str
+    ) -> None:
         """
         Store a hook from a received file message.
 
@@ -905,9 +903,17 @@ class Session:
         :param data: hook data
         :return: nothing
         """
-        # hack to conform with old logic until updated
-        state = f":{state}"
-        self.set_hook(state, file_name, source_name, data)
+        logging.info(
+            "setting state hook: %s - %s from %s", state, file_name, source_name
+        )
+        hook = file_name, data
+        state_hooks = self._hooks.setdefault(state, [])
+        state_hooks.append(hook)
+
+        # immediately run a hook if it is in the current state
+        if self.state == state:
+            logging.info("immediately running new state hook")
+            self.run_hook(hook)
 
     def add_node_file(
         self, node_id: int, source_name: str, file_name: str, data: str
@@ -1072,10 +1078,8 @@ class Session:
         :param send_event: if true, generate core API event messages
         :return: nothing
         """
-        state_value = state.value
         state_name = state.name
-
-        if self.state == state_value:
+        if self.state == state:
             logging.info(
                 "session(%s) is already in state: %s, skipping change",
                 self.id,
@@ -1083,33 +1087,32 @@ class Session:
             )
             return
 
-        self.state = state_value
+        self.state = state
         self._state_time = time.monotonic()
         logging.info("changing session(%s) to state %s", self.id, state_name)
-
-        self.write_state(state_value)
-        self.run_hooks(state_value)
-        self.run_state_hooks(state_value)
+        self.write_state(state)
+        self.run_hooks(state)
+        self.run_state_hooks(state)
 
         if send_event:
-            event_data = EventData(event_type=state_value, time=str(time.monotonic()))
+            event_data = EventData(event_type=state, time=str(time.monotonic()))
             self.broadcast_event(event_data)
 
-    def write_state(self, state: int) -> None:
+    def write_state(self, state: EventTypes) -> None:
         """
-        Write the current state to a state file in the session dir.
+        Write the state to a state file in the session dir.
 
         :param state: state to write to file
         :return: nothing
         """
         try:
             state_file = open(self._state_file, "w")
-            state_file.write(f"{state} {EventTypes(self.state).name}\n")
+            state_file.write(f"{state.value} {state.name}\n")
             state_file.close()
         except IOError:
-            logging.exception("error writing state file: %s", state)
+            logging.exception("error writing state file: %s", state.name)
 
-    def run_hooks(self, state: int) -> None:
+    def run_hooks(self, state: EventTypes) -> None:
         """
         Run hook scripts upon changing states. If hooks is not specified, run all hooks
         in the given state.
@@ -1213,7 +1216,7 @@ class Session:
         except (OSError, subprocess.CalledProcessError):
             logging.exception("error running hook: %s", file_name)
 
-    def run_state_hooks(self, state: int) -> None:
+    def run_state_hooks(self, state: EventTypes) -> None:
         """
         Run state hooks.
 
@@ -1224,16 +1227,17 @@ class Session:
             try:
                 hook(state)
             except Exception:
-                state_name = EventTypes(self.state).name
                 message = (
-                    f"exception occured when running {state_name} state hook: {hook}"
+                    f"exception occured when running {state.name} state hook: {hook}"
                 )
                 logging.exception(message)
                 self.exception(
                     ExceptionLevels.ERROR, "Session.run_state_hooks", None, message
                 )
 
-    def add_state_hook(self, state: int, hook: Callable[[int], None]) -> None:
+    def add_state_hook(
+        self, state: EventTypes, hook: Callable[[EventTypes], None]
+    ) -> None:
         """
         Add a state hook.
 
@@ -1260,14 +1264,14 @@ class Session:
         hooks = self._state_hooks.setdefault(state, [])
         hooks.remove(hook)
 
-    def runtime_state_hook(self, state: int) -> None:
+    def runtime_state_hook(self, state: EventTypes) -> None:
         """
         Runtime state hook check.
 
         :param state: state to check
         :return: nothing
         """
-        if state == EventTypes.RUNTIME_STATE.value:
+        if state == EventTypes.RUNTIME_STATE:
             self.emane.poststartup()
 
             # create session deployed xml
@@ -1511,7 +1515,7 @@ class Session:
             self.mobility.startup()
 
             # notify listeners that instantiation is complete
-            event = EventData(event_type=EventTypes.INSTANTIATION_COMPLETE.value)
+            event = EventData(event_type=EventTypes.INSTANTIATION_COMPLETE)
             self.broadcast_event(event)
 
             # assume either all nodes have booted already, or there are some
@@ -1554,9 +1558,9 @@ class Session:
         logging.debug(
             "session(%s) checking if not in runtime state, current state: %s",
             self.id,
-            EventTypes(self.state).name,
+            self.state.name,
         )
-        if self.state == EventTypes.RUNTIME_STATE.value:
+        if self.state == EventTypes.RUNTIME_STATE:
             logging.info("valid runtime state found, returning")
             return
 
@@ -1893,7 +1897,7 @@ class Session:
         Return the current time we have been in the runtime state, or zero
         if not in runtime.
         """
-        if self.state == EventTypes.RUNTIME_STATE.value:
+        if self.state == EventTypes.RUNTIME_STATE:
             return time.monotonic() - self._state_time
         else:
             return 0.0
diff --git a/daemon/core/emulator/sessionconfig.py b/daemon/core/emulator/sessionconfig.py
index 5f2d5916..ffeccdc4 100644
--- a/daemon/core/emulator/sessionconfig.py
+++ b/daemon/core/emulator/sessionconfig.py
@@ -57,7 +57,7 @@ class SessionConfig(ConfigurableManager, ConfigurableOptions):
             label="SDT3D URL",
         ),
     ]
-    config_type = RegisterTlvs.UTILITY.value
+    config_type = RegisterTlvs.UTILITY
 
     def __init__(self) -> None:
         super().__init__()
diff --git a/daemon/core/location/geo.py b/daemon/core/location/geo.py
index 7d3aea22..1f78f329 100644
--- a/daemon/core/location/geo.py
+++ b/daemon/core/location/geo.py
@@ -21,7 +21,7 @@ class GeoLocation:
     """
 
     name = "location"
-    config_type = RegisterTlvs.UTILITY.value
+    config_type = RegisterTlvs.UTILITY
 
     def __init__(self) -> None:
         """
diff --git a/daemon/core/location/mobility.py b/daemon/core/location/mobility.py
index bf02385a..62d954fa 100644
--- a/daemon/core/location/mobility.py
+++ b/daemon/core/location/mobility.py
@@ -36,7 +36,7 @@ class MobilityManager(ModelManager):
     """
 
     name = "MobilityManager"
-    config_type = RegisterTlvs.WIRELESS.value
+    config_type = RegisterTlvs.WIRELESS
 
     def __init__(self, session: "Session") -> None:
         """
@@ -121,10 +121,7 @@ class MobilityManager(ModelManager):
                 logging.warning("Ignoring event for unknown model '%s'", model)
                 continue
 
-            if cls.config_type in [
-                RegisterTlvs.WIRELESS.value,
-                RegisterTlvs.MOBILITY.value,
-            ]:
+            if cls.config_type in [RegisterTlvs.WIRELESS, RegisterTlvs.MOBILITY]:
                 model = node.mobility
             else:
                 continue
@@ -142,17 +139,11 @@ class MobilityManager(ModelManager):
                 )
                 continue
 
-            if (
-                event_type == EventTypes.STOP.value
-                or event_type == EventTypes.RESTART.value
-            ):
+            if event_type in [EventTypes.STOP, EventTypes.RESTART]:
                 model.stop(move_initial=True)
-            if (
-                event_type == EventTypes.START.value
-                or event_type == EventTypes.RESTART.value
-            ):
+            if event_type in [EventTypes.START, EventTypes.RESTART]:
                 model.start()
-            if event_type == EventTypes.PAUSE.value:
+            if event_type == EventTypes.PAUSE:
                 model.pause()
 
     def sendevent(self, model: "WayPointMobility") -> None:
@@ -163,13 +154,13 @@ class MobilityManager(ModelManager):
         :param model: mobility model to send event for
         :return: nothing
         """
-        event_type = EventTypes.NONE.value
+        event_type = EventTypes.NONE
         if model.state == model.STATE_STOPPED:
-            event_type = EventTypes.STOP.value
+            event_type = EventTypes.STOP
         elif model.state == model.STATE_RUNNING:
-            event_type = EventTypes.START.value
+            event_type = EventTypes.START
         elif model.state == model.STATE_PAUSED:
-            event_type = EventTypes.PAUSE.value
+            event_type = EventTypes.PAUSE
 
         start_time = int(model.lasttime - model.timezero)
         end_time = int(model.endtime)
@@ -212,7 +203,7 @@ class WirelessModel(ConfigurableOptions):
     Used for managing arbitrary configuration parameters.
     """
 
-    config_type = RegisterTlvs.WIRELESS.value
+    config_type = RegisterTlvs.WIRELESS
     bitmap = None
     position_callback = None
 
@@ -226,7 +217,7 @@ class WirelessModel(ConfigurableOptions):
         self.session = session
         self.id = _id
 
-    def all_link_data(self, flags: int) -> List:
+    def all_link_data(self, flags: MessageFlags = MessageFlags.NONE) -> List:
         """
         May be used if the model can populate the GUI with wireless (green)
         link lines.
@@ -486,7 +477,10 @@ class BasicRangeModel(WirelessModel):
         return True
 
     def create_link_data(
-        self, interface1: CoreInterface, interface2: CoreInterface, message_type: int
+        self,
+        interface1: CoreInterface,
+        interface2: CoreInterface,
+        message_type: MessageFlags,
     ) -> LinkData:
         """
         Create a wireless link/unlink data message.
@@ -501,7 +495,7 @@ class BasicRangeModel(WirelessModel):
             node1_id=interface1.node.id,
             node2_id=interface2.node.id,
             network_id=self.wlan.id,
-            link_type=LinkTypes.WIRELESS.value,
+            link_type=LinkTypes.WIRELESS,
         )
 
     def sendlinkmsg(
@@ -516,14 +510,14 @@ class BasicRangeModel(WirelessModel):
         :return: nothing
         """
         if unlink:
-            message_type = MessageFlags.DELETE.value
+            message_type = MessageFlags.DELETE
         else:
-            message_type = MessageFlags.ADD.value
+            message_type = MessageFlags.ADD
 
         link_data = self.create_link_data(netif, netif2, message_type)
         self.session.broadcast_link(link_data)
 
-    def all_link_data(self, flags: int) -> List[LinkData]:
+    def all_link_data(self, flags: MessageFlags = MessageFlags.NONE) -> List[LinkData]:
         """
         Return a list of wireless link messages for when the GUI reconnects.
 
@@ -578,7 +572,7 @@ class WayPointMobility(WirelessModel):
     """
 
     name = "waypoint"
-    config_type = RegisterTlvs.MOBILITY.value
+    config_type = RegisterTlvs.MOBILITY
 
     STATE_STOPPED = 0
     STATE_RUNNING = 1
@@ -818,7 +812,7 @@ class WayPointMobility(WirelessModel):
         :return: nothing
         """
         node.position.set(x, y, z)
-        node_data = node.data(message_type=0)
+        node_data = node.data()
         self.session.broadcast_node(node_data)
 
     def setendtime(self) -> None:
diff --git a/daemon/core/nodes/base.py b/daemon/core/nodes/base.py
index 1c9417a9..8f5354f2 100644
--- a/daemon/core/nodes/base.py
+++ b/daemon/core/nodes/base.py
@@ -14,7 +14,7 @@ from core import utils
 from core.configservice.dependencies import ConfigServiceDependencies
 from core.constants import MOUNT_BIN, VNODED_BIN
 from core.emulator.data import LinkData, NodeData
-from core.emulator.enumerations import LinkTypes, NodeTypes
+from core.emulator.enumerations import LinkTypes, MessageFlags, NodeTypes
 from core.errors import CoreCommandError, CoreError
 from core.nodes import client
 from core.nodes.interface import CoreInterface, TunTap, Veth
@@ -193,7 +193,7 @@ class NodeBase:
 
     def data(
         self,
-        message_type: int,
+        message_type: MessageFlags = MessageFlags.NONE,
         lat: float = None,
         lon: float = None,
         alt: float = None,
@@ -244,7 +244,7 @@ class NodeBase:
 
         return node_data
 
-    def all_link_data(self, flags: int) -> List:
+    def all_link_data(self, flags: MessageFlags = MessageFlags.NONE) -> List[LinkData]:
         """
         Build CORE Link data for this object. There is no default
         method for PyCoreObjs as PyCoreNodes do not implement this but
@@ -472,7 +472,7 @@ class CoreNode(CoreNodeBase):
     Provides standard core node logic.
     """
 
-    apitype = NodeTypes.DEFAULT.value
+    apitype = NodeTypes.DEFAULT
     valid_address_types = {"inet", "inet6", "inet6link"}
 
     def __init__(
@@ -982,7 +982,7 @@ class CoreNetworkBase(NodeBase):
     Base class for networks
     """
 
-    linktype = LinkTypes.WIRED.value
+    linktype = LinkTypes.WIRED
     is_emane = False
 
     def __init__(
@@ -1069,7 +1069,7 @@ class CoreNetworkBase(NodeBase):
         with self._linked_lock:
             del self._linked[netif]
 
-    def all_link_data(self, flags: int) -> List[LinkData]:
+    def all_link_data(self, flags: MessageFlags = MessageFlags.NONE) -> List[LinkData]:
         """
         Build link data objects for this network. Each link object describes a link
         between this network and a node.
diff --git a/daemon/core/nodes/docker.py b/daemon/core/nodes/docker.py
index 4622f4f5..60adfe32 100644
--- a/daemon/core/nodes/docker.py
+++ b/daemon/core/nodes/docker.py
@@ -72,7 +72,7 @@ class DockerClient:
 
 
 class DockerNode(CoreNode):
-    apitype = NodeTypes.DOCKER.value
+    apitype = NodeTypes.DOCKER
 
     def __init__(
         self,
diff --git a/daemon/core/nodes/interface.py b/daemon/core/nodes/interface.py
index ea8e5012..8da7c95b 100644
--- a/daemon/core/nodes/interface.py
+++ b/daemon/core/nodes/interface.py
@@ -7,6 +7,7 @@ import time
 from typing import TYPE_CHECKING, Callable, Dict, List, Tuple
 
 from core import utils
+from core.emulator.enumerations import MessageFlags
 from core.errors import CoreCommandError
 from core.nodes.netclient import get_net_client
 
@@ -552,7 +553,7 @@ class GreTap(CoreInterface):
         """
         return None
 
-    def all_link_data(self, flags: int) -> List:
+    def all_link_data(self, flags: MessageFlags = MessageFlags.NONE) -> List:
         """
         Retrieve link data.
 
diff --git a/daemon/core/nodes/lxd.py b/daemon/core/nodes/lxd.py
index b64c0206..3ca399b5 100644
--- a/daemon/core/nodes/lxd.py
+++ b/daemon/core/nodes/lxd.py
@@ -66,7 +66,7 @@ class LxdClient:
 
 
 class LxcNode(CoreNode):
-    apitype = NodeTypes.LXC.value
+    apitype = NodeTypes.LXC
 
     def __init__(
         self,
diff --git a/daemon/core/nodes/network.py b/daemon/core/nodes/network.py
index 9547e6dc..dded924d 100644
--- a/daemon/core/nodes/network.py
+++ b/daemon/core/nodes/network.py
@@ -12,7 +12,7 @@ import netaddr
 from core import utils
 from core.constants import EBTABLES_BIN, TC_BIN
 from core.emulator.data import LinkData, NodeData
-from core.emulator.enumerations import LinkTypes, NodeTypes, RegisterTlvs
+from core.emulator.enumerations import LinkTypes, MessageFlags, NodeTypes, RegisterTlvs
 from core.errors import CoreCommandError, CoreError
 from core.nodes.base import CoreNetworkBase
 from core.nodes.interface import CoreInterface, GreTap, Veth
@@ -848,7 +848,7 @@ class CtrlNet(CoreNetwork):
 
         super().shutdown()
 
-    def all_link_data(self, flags: int) -> List[LinkData]:
+    def all_link_data(self, flags: MessageFlags = MessageFlags.NONE) -> List[LinkData]:
         """
         Do not include CtrlNet in link messages describing this session.
 
@@ -899,7 +899,7 @@ class PtpNet(CoreNetwork):
         """
         return None
 
-    def all_link_data(self, flags: int) -> List[LinkData]:
+    def all_link_data(self, flags: MessageFlags = MessageFlags.NONE) -> List[LinkData]:
         """
         Build CORE API TLVs for a point-to-point link. One Link message
         describes this network.
@@ -999,7 +999,7 @@ class SwitchNode(CoreNetwork):
     Provides switch functionality within a core node.
     """
 
-    apitype = NodeTypes.SWITCH.value
+    apitype = NodeTypes.SWITCH
     policy = "ACCEPT"
     type = "lanswitch"
 
@@ -1010,7 +1010,7 @@ class HubNode(CoreNetwork):
     ports by turning off MAC address learning.
     """
 
-    apitype = NodeTypes.HUB.value
+    apitype = NodeTypes.HUB
     policy = "ACCEPT"
     type = "hub"
 
@@ -1029,8 +1029,8 @@ class WlanNode(CoreNetwork):
     Provides wireless lan functionality within a core node.
     """
 
-    apitype = NodeTypes.WIRELESS_LAN.value
-    linktype = LinkTypes.WIRED.value
+    apitype = NodeTypes.WIRELESS_LAN
+    linktype = LinkTypes.WIRED
     policy = "DROP"
     type = "wlan"
 
@@ -1090,13 +1090,13 @@ class WlanNode(CoreNetwork):
         :return: nothing
         """
         logging.debug("node(%s) setting model: %s", self.name, model.name)
-        if model.config_type == RegisterTlvs.WIRELESS.value:
+        if model.config_type == RegisterTlvs.WIRELESS:
             self.model = model(session=self.session, _id=self.id)
             for netif in self.netifs():
                 netif.poshook = self.model.position_callback
                 netif.setposition()
             self.updatemodel(config)
-        elif model.config_type == RegisterTlvs.MOBILITY.value:
+        elif model.config_type == RegisterTlvs.MOBILITY:
             self.mobility = model(session=self.session, _id=self.id)
             self.mobility.update_config(config)
 
@@ -1115,7 +1115,7 @@ class WlanNode(CoreNetwork):
         for netif in self.netifs():
             netif.setposition()
 
-    def all_link_data(self, flags: int) -> List[LinkData]:
+    def all_link_data(self, flags: MessageFlags = MessageFlags.NONE) -> List[LinkData]:
         """
         Retrieve all link data.
 
@@ -1133,6 +1133,6 @@ class TunnelNode(GreTapBridge):
     Provides tunnel functionality in a core node.
     """
 
-    apitype = NodeTypes.TUNNEL.value
+    apitype = NodeTypes.TUNNEL
     policy = "ACCEPT"
     type = "tunnel"
diff --git a/daemon/core/nodes/physical.py b/daemon/core/nodes/physical.py
index 4d9d21f4..e8c999c6 100644
--- a/daemon/core/nodes/physical.py
+++ b/daemon/core/nodes/physical.py
@@ -264,7 +264,7 @@ class Rj45Node(CoreNodeBase, CoreInterface):
     network.
     """
 
-    apitype = NodeTypes.RJ45.value
+    apitype = NodeTypes.RJ45
     type = "rj45"
 
     def __init__(
diff --git a/daemon/core/plugins/sdt.py b/daemon/core/plugins/sdt.py
index 1ccf40a5..a759228d 100644
--- a/daemon/core/plugins/sdt.py
+++ b/daemon/core/plugins/sdt.py
@@ -24,7 +24,7 @@ if TYPE_CHECKING:
 def link_data_params(link_data: LinkData) -> Tuple[int, int, bool]:
     node_one = link_data.node1_id
     node_two = link_data.node2_id
-    is_wireless = link_data.link_type == LinkTypes.WIRELESS.value
+    is_wireless = link_data.link_type == LinkTypes.WIRELESS
     return node_one, node_two, is_wireless
 
 
@@ -90,7 +90,7 @@ class Sdt:
         self.address = (self.url.hostname, self.url.port)
         self.protocol = self.url.scheme
 
-    def connect(self, flags: int = 0) -> bool:
+    def connect(self) -> bool:
         """
         Connect to the SDT address/port if enabled.
 
@@ -100,7 +100,7 @@ class Sdt:
             return False
         if self.connected:
             return True
-        if self.session.state == EventTypes.SHUTDOWN_STATE.value:
+        if self.session.state == EventTypes.SHUTDOWN_STATE:
             return False
 
         self.seturl()
@@ -122,7 +122,7 @@ class Sdt:
 
         self.connected = True
         # refresh all objects in SDT3D when connecting after session start
-        if not flags & MessageFlags.ADD.value and not self.sendobjs():
+        if not self.sendobjs():
             return False
         return True
 
@@ -210,7 +210,7 @@ class Sdt:
                 self.add_node(node)
 
             for net in nets:
-                all_links = net.all_link_data(flags=MessageFlags.ADD.value)
+                all_links = net.all_link_data(flags=MessageFlags.ADD)
                 for link_data in all_links:
                     is_wireless = isinstance(net, (WlanNode, EmaneNet))
                     if is_wireless and link_data.node1_id == net.id:
@@ -302,7 +302,7 @@ class Sdt:
             return
 
         # delete node
-        if node_data.message_type == MessageFlags.DELETE.value:
+        if node_data.message_type == MessageFlags.DELETE:
             self.cmd(f"delete node,{node_data.id}")
         else:
             x = node_data.x_position
@@ -375,9 +375,9 @@ class Sdt:
         :param link_data: link data to handle
         :return: nothing
         """
-        if link_data.message_type == MessageFlags.ADD.value:
+        if link_data.message_type == MessageFlags.ADD:
             params = link_data_params(link_data)
             self.add_link(*params)
-        elif link_data.message_type == MessageFlags.DELETE.value:
+        elif link_data.message_type == MessageFlags.DELETE:
             params = link_data_params(link_data)
             self.delete_link(*params[:2])
diff --git a/daemon/core/services/coreservices.py b/daemon/core/services/coreservices.py
index a561b843..6323ceab 100644
--- a/daemon/core/services/coreservices.py
+++ b/daemon/core/services/coreservices.py
@@ -315,7 +315,7 @@ class CoreServices:
     """
 
     name = "services"
-    config_type = RegisterTlvs.UTILITY.value
+    config_type = RegisterTlvs.UTILITY
 
     def __init__(self, session: "Session") -> None:
         """
@@ -672,7 +672,7 @@ class CoreServices:
 
         filetypestr = "service:%s" % service.name
         return FileData(
-            message_type=MessageFlags.ADD.value,
+            message_type=MessageFlags.ADD,
             node=node.id,
             name=filename,
             type=filetypestr,
diff --git a/daemon/core/services/quagga.py b/daemon/core/services/quagga.py
index 11de9c54..7979dd23 100644
--- a/daemon/core/services/quagga.py
+++ b/daemon/core/services/quagga.py
@@ -551,7 +551,7 @@ class Babel(QuaggaService):
 
     @classmethod
     def generatequaggaifcconfig(cls, node, ifc):
-        if ifc.net and ifc.net.linktype == LinkTypes.WIRELESS.value:
+        if ifc.net and ifc.net.linktype == LinkTypes.WIRELESS:
             return "  babel wireless\n  no babel split-horizon\n"
         else:
             return "  babel wired\n  babel split-horizon\n"
diff --git a/daemon/core/xml/corexml.py b/daemon/core/xml/corexml.py
index 8eab98c2..68426905 100644
--- a/daemon/core/xml/corexml.py
+++ b/daemon/core/xml/corexml.py
@@ -8,7 +8,7 @@ import core.nodes.physical
 from core.emane.nodes import EmaneNet
 from core.emulator.data import LinkData
 from core.emulator.emudata import InterfaceData, LinkOptions, NodeOptions
-from core.emulator.enumerations import NodeTypes
+from core.emulator.enumerations import EventTypes, NodeTypes
 from core.nodes.base import CoreNetworkBase, CoreNodeBase, NodeBase
 from core.nodes.docker import DockerNode
 from core.nodes.lxd import LxcNode
@@ -260,7 +260,7 @@ class NetworkElement(NodeElement):
 
     def add_type(self) -> None:
         if self.node.apitype:
-            node_type = NodeTypes(self.node.apitype).name
+            node_type = self.node.apitype.name
         else:
             node_type = self.node.__class__.__name__
         add_attribute(self.element, "type", node_type)
@@ -324,7 +324,7 @@ class CoreXmlWriter:
             for file_name, data in self.session._hooks[state]:
                 hook = etree.SubElement(hooks, "hook")
                 add_attribute(hook, "name", file_name)
-                add_attribute(hook, "state", state)
+                add_attribute(hook, "state", state.value)
                 hook.text = data
 
         if hooks.getchildren():
@@ -476,7 +476,7 @@ class CoreXmlWriter:
                 self.write_device(node)
 
             # add known links
-            links.extend(node.all_link_data(0))
+            links.extend(node.all_link_data())
 
         return links
 
@@ -666,13 +666,11 @@ class CoreXmlReader:
 
         for hook in session_hooks.iterchildren():
             name = hook.get("name")
-            state = hook.get("state")
+            state = get_int(hook, "state")
+            state = EventTypes(state)
             data = hook.text
-            hook_type = f"hook:{state}"
             logging.info("reading hook: state(%s) name(%s)", state, name)
-            self.session.set_hook(
-                hook_type, file_name=name, source_name=None, data=data
-            )
+            self.session.add_hook(state, name, None, data)
 
     def read_session_origin(self) -> None:
         session_origin = self.scenario.find("session_origin")
diff --git a/daemon/scripts/core-daemon b/daemon/scripts/core-daemon
index 6b55c14f..866c5472 100755
--- a/daemon/scripts/core-daemon
+++ b/daemon/scripts/core-daemon
@@ -17,8 +17,8 @@ from core import constants
 from core.api.grpc.server import CoreGrpcServer
 from core.api.tlv.corehandlers import CoreHandler, CoreUdpHandler
 from core.api.tlv.coreserver import CoreServer, CoreUdpServer
+from core.api.tlv.enumerations import CORE_API_PORT
 from core.constants import CORE_CONF_DIR, COREDPY_VERSION
-from core.emulator.enumerations import CORE_API_PORT
 from core.utils import close_onexec, load_logging_config
 
 
diff --git a/daemon/scripts/coresendmsg b/daemon/scripts/coresendmsg
index c8dccfd7..a909522f 100755
--- a/daemon/scripts/coresendmsg
+++ b/daemon/scripts/coresendmsg
@@ -9,12 +9,8 @@ import socket
 import sys
 
 from core.api.tlv import coreapi
-from core.emulator.enumerations import (
-    CORE_API_PORT,
-    MessageFlags,
-    MessageTypes,
-    SessionTlvs,
-)
+from core.api.tlv.enumerations import CORE_API_PORT, MessageTypes, SessionTlvs
+from core.emulator.enumerations import MessageFlags
 
 
 def print_available_tlvs(t, tlv_class):
diff --git a/daemon/tests/test_core.py b/daemon/tests/test_core.py
index 80cf6787..cc9ba2a4 100644
--- a/daemon/tests/test_core.py
+++ b/daemon/tests/test_core.py
@@ -114,7 +114,7 @@ class TestCore:
         session.instantiate()
 
         # check link data gets generated
-        assert ptp_node.all_link_data(MessageFlags.ADD.value)
+        assert ptp_node.all_link_data(MessageFlags.ADD)
 
         # check common nets exist between linked nodes
         assert node_one.commonnets(node_two)
diff --git a/daemon/tests/test_grpc.py b/daemon/tests/test_grpc.py
index d26c46e4..6feacac3 100644
--- a/daemon/tests/test_grpc.py
+++ b/daemon/tests/test_grpc.py
@@ -7,16 +7,12 @@ from mock import patch
 
 from core.api.grpc import core_pb2
 from core.api.grpc.client import CoreGrpcClient, InterfaceHelper
-from core.config import ConfigShim
+from core.api.tlv.dataconversion import ConfigShim
+from core.api.tlv.enumerations import ConfigFlags
 from core.emane.ieee80211abg import EmaneIeee80211abgModel
 from core.emulator.data import EventData
 from core.emulator.emudata import NodeOptions
-from core.emulator.enumerations import (
-    ConfigFlags,
-    EventTypes,
-    ExceptionLevels,
-    NodeTypes,
-)
+from core.emulator.enumerations import EventTypes, ExceptionLevels, NodeTypes
 from core.errors import CoreError
 from core.location.mobility import BasicRangeModel, Ns2ScriptedMobility
 from core.xml.corexml import CoreXmlWriter
@@ -127,7 +123,7 @@ class TestGrpc:
         assert wlan_node.id in session.nodes
         assert session.nodes[node_one.id].netif(0) is not None
         assert session.nodes[node_two.id].netif(0) is not None
-        hook_file, hook_data = session._hooks[core_pb2.SessionState.RUNTIME][0]
+        hook_file, hook_data = session._hooks[EventTypes.RUNTIME_STATE][0]
         assert hook_file == hook.file
         assert hook_data == hook.data
         assert session.location.refxyz == (location_x, location_y, location_z)
@@ -169,7 +165,7 @@ class TestGrpc:
         assert isinstance(response.state, int)
         session = grpc_server.coreemu.sessions.get(response.session_id)
         assert session is not None
-        assert session.state == response.state
+        assert session.state == EventTypes(response.state)
         if session_id is not None:
             assert response.session_id == session_id
             assert session.id == session_id
@@ -341,7 +337,7 @@ class TestGrpc:
 
         # then
         assert response.result is True
-        assert session.state == core_pb2.SessionState.DEFINITION
+        assert session.state == EventTypes.DEFINITION_STATE
 
     def test_add_node(self, grpc_server):
         # given
@@ -447,7 +443,7 @@ class TestGrpc:
         session = grpc_server.coreemu.create_session()
         file_name = "test"
         file_data = "echo hello"
-        session.add_hook(EventTypes.RUNTIME_STATE.value, file_name, None, file_data)
+        session.add_hook(EventTypes.RUNTIME_STATE, file_name, None, file_data)
 
         # then
         with client.context_connect():
@@ -540,7 +536,7 @@ class TestGrpc:
         session = grpc_server.coreemu.create_session()
         switch = session.add_node(_type=NodeTypes.SWITCH)
         node = session.add_node()
-        assert len(switch.all_link_data(0)) == 0
+        assert len(switch.all_link_data()) == 0
 
         # then
         interface = interface_helper.create_interface(node.id, 0)
@@ -549,7 +545,7 @@ class TestGrpc:
 
         # then
         assert response.result is True
-        assert len(switch.all_link_data(0)) == 1
+        assert len(switch.all_link_data()) == 1
 
     def test_add_link_exception(self, grpc_server, interface_helper):
         # given
@@ -572,7 +568,7 @@ class TestGrpc:
         interface = ip_prefixes.create_interface(node)
         session.add_link(node.id, switch.id, interface)
         options = core_pb2.LinkOptions(bandwidth=30000)
-        link = switch.all_link_data(0)[0]
+        link = switch.all_link_data()[0]
         assert options.bandwidth != link.bandwidth
 
         # then
@@ -583,7 +579,7 @@ class TestGrpc:
 
         # then
         assert response.result is True
-        link = switch.all_link_data(0)[0]
+        link = switch.all_link_data()[0]
         assert options.bandwidth == link.bandwidth
 
     def test_delete_link(self, grpc_server, ip_prefixes):
@@ -986,7 +982,7 @@ class TestGrpc:
         client = CoreGrpcClient()
         session = grpc_server.coreemu.create_session()
         node = session.add_node()
-        node_data = node.data(message_type=0)
+        node_data = node.data()
         queue = Queue()
 
         def handle_event(event_data):
@@ -1011,7 +1007,7 @@ class TestGrpc:
         node = session.add_node()
         interface = ip_prefixes.create_interface(node)
         session.add_link(node.id, wlan.id, interface)
-        link_data = wlan.all_link_data(0)[0]
+        link_data = wlan.all_link_data()[0]
         queue = Queue()
 
         def handle_event(event_data):
@@ -1065,7 +1061,7 @@ class TestGrpc:
             client.events(session.id, handle_event)
             time.sleep(0.1)
             event = EventData(
-                event_type=EventTypes.RUNTIME_STATE.value, time=str(time.monotonic())
+                event_type=EventTypes.RUNTIME_STATE, time=str(time.monotonic())
             )
             session.broadcast_event(event)
 
diff --git a/daemon/tests/test_gui.py b/daemon/tests/test_gui.py
index a47aba75..481a0fa9 100644
--- a/daemon/tests/test_gui.py
+++ b/daemon/tests/test_gui.py
@@ -10,21 +10,18 @@ import pytest
 from mock import MagicMock
 
 from core.api.tlv import coreapi
-from core.emane.ieee80211abg import EmaneIeee80211abgModel
-from core.emulator.enumerations import (
+from core.api.tlv.enumerations import (
     ConfigFlags,
     ConfigTlvs,
     EventTlvs,
-    EventTypes,
     ExecuteTlvs,
     FileTlvs,
     LinkTlvs,
-    MessageFlags,
     NodeTlvs,
-    NodeTypes,
-    RegisterTlvs,
     SessionTlvs,
 )
+from core.emane.ieee80211abg import EmaneIeee80211abgModel
+from core.emulator.enumerations import EventTypes, MessageFlags, NodeTypes, RegisterTlvs
 from core.errors import CoreError
 from core.location.mobility import BasicRangeModel
 
@@ -117,7 +114,7 @@ class TestGui:
         coretlv.handle_message(message)
 
         switch_node = coretlv.session.get_node(switch)
-        all_links = switch_node.all_link_data(0)
+        all_links = switch_node.all_link_data()
         assert len(all_links) == 1
 
     def test_link_add_net_to_node(self, coretlv):
@@ -141,7 +138,7 @@ class TestGui:
         coretlv.handle_message(message)
 
         switch_node = coretlv.session.get_node(switch)
-        all_links = switch_node.all_link_data(0)
+        all_links = switch_node.all_link_data()
         assert len(all_links) == 1
 
     def test_link_add_node_to_node(self, coretlv):
@@ -171,7 +168,7 @@ class TestGui:
         all_links = []
         for node_id in coretlv.session.nodes:
             node = coretlv.session.nodes[node_id]
-            all_links += node.all_link_data(0)
+            all_links += node.all_link_data()
         assert len(all_links) == 1
 
     def test_link_update(self, coretlv):
@@ -193,7 +190,7 @@ class TestGui:
         )
         coretlv.handle_message(message)
         switch_node = coretlv.session.get_node(switch)
-        all_links = switch_node.all_link_data(0)
+        all_links = switch_node.all_link_data()
         assert len(all_links) == 1
         link = all_links[0]
         assert link.bandwidth is None
@@ -211,7 +208,7 @@ class TestGui:
         coretlv.handle_message(message)
 
         switch_node = coretlv.session.get_node(switch)
-        all_links = switch_node.all_link_data(0)
+        all_links = switch_node.all_link_data()
         assert len(all_links) == 1
         link = all_links[0]
         assert link.bandwidth == bandwidth
@@ -240,7 +237,7 @@ class TestGui:
         all_links = []
         for node_id in coretlv.session.nodes:
             node = coretlv.session.nodes[node_id]
-            all_links += node.all_link_data(0)
+            all_links += node.all_link_data()
         assert len(all_links) == 1
 
         message = coreapi.CoreLinkMessage.create(
@@ -257,7 +254,7 @@ class TestGui:
         all_links = []
         for node_id in coretlv.session.nodes:
             node = coretlv.session.nodes[node_id]
-            all_links += node.all_link_data(0)
+            all_links += node.all_link_data()
         assert len(all_links) == 0
 
     def test_link_delete_node_to_net(self, coretlv):
@@ -279,7 +276,7 @@ class TestGui:
         )
         coretlv.handle_message(message)
         switch_node = coretlv.session.get_node(switch)
-        all_links = switch_node.all_link_data(0)
+        all_links = switch_node.all_link_data()
         assert len(all_links) == 1
 
         message = coreapi.CoreLinkMessage.create(
@@ -293,7 +290,7 @@ class TestGui:
         coretlv.handle_message(message)
 
         switch_node = coretlv.session.get_node(switch)
-        all_links = switch_node.all_link_data(0)
+        all_links = switch_node.all_link_data()
         assert len(all_links) == 0
 
     def test_link_delete_net_to_node(self, coretlv):
@@ -315,7 +312,7 @@ class TestGui:
         )
         coretlv.handle_message(message)
         switch_node = coretlv.session.get_node(switch)
-        all_links = switch_node.all_link_data(0)
+        all_links = switch_node.all_link_data()
         assert len(all_links) == 1
 
         message = coreapi.CoreLinkMessage.create(
@@ -329,7 +326,7 @@ class TestGui:
         coretlv.handle_message(message)
 
         switch_node = coretlv.session.get_node(switch)
-        all_links = switch_node.all_link_data(0)
+        all_links = switch_node.all_link_data()
         assert len(all_links) == 0
 
     def test_session_update(self, coretlv):
@@ -376,14 +373,14 @@ class TestGui:
         assert len(coretlv.coreemu.sessions) == 0
 
     def test_file_hook_add(self, coretlv):
-        state = EventTypes.DATACOLLECT_STATE.value
+        state = EventTypes.DATACOLLECT_STATE
         assert coretlv.session._hooks.get(state) is None
         file_name = "test.sh"
         file_data = "echo hello"
         message = coreapi.CoreFileMessage.create(
             MessageFlags.ADD.value,
             [
-                (FileTlvs.TYPE, f"hook:{state}"),
+                (FileTlvs.TYPE, f"hook:{state.value}"),
                 (FileTlvs.NAME, file_name),
                 (FileTlvs.DATA, file_data),
             ],
@@ -514,7 +511,7 @@ class TestGui:
 
         coretlv.handle_message(message)
 
-        assert coretlv.session.state == state.value
+        assert coretlv.session.state == state
 
     def test_event_schedule(self, coretlv):
         coretlv.session.add_event = mock.MagicMock()
diff --git a/daemon/tests/test_links.py b/daemon/tests/test_links.py
index ceef3a02..d32a1c5f 100644
--- a/daemon/tests/test_links.py
+++ b/daemon/tests/test_links.py
@@ -43,7 +43,7 @@ class TestLinks:
         session.add_link(node_one.id, node_two.id, interface_one)
 
         # then
-        assert node_two.all_link_data(0)
+        assert node_two.all_link_data()
         assert node_one.netif(interface_one.id)
 
     def test_net_to_node(self, session, ip_prefixes):
@@ -56,7 +56,7 @@ class TestLinks:
         session.add_link(node_one.id, node_two.id, interface_two=interface_two)
 
         # then
-        assert node_one.all_link_data(0)
+        assert node_one.all_link_data()
         assert node_two.netif(interface_two.id)
 
     def test_net_to_net(self, session):
@@ -68,7 +68,7 @@ class TestLinks:
         session.add_link(node_one.id, node_two.id)
 
         # then
-        assert node_one.all_link_data(0)
+        assert node_one.all_link_data()
 
     def test_link_update(self, session, ip_prefixes):
         # given
diff --git a/daemon/tests/test_xml.py b/daemon/tests/test_xml.py
index 496623a6..783e2722 100644
--- a/daemon/tests/test_xml.py
+++ b/daemon/tests/test_xml.py
@@ -3,7 +3,7 @@ from xml.etree import ElementTree
 import pytest
 
 from core.emulator.emudata import LinkOptions, NodeOptions
-from core.emulator.enumerations import NodeTypes
+from core.emulator.enumerations import EventTypes, NodeTypes
 from core.errors import CoreError
 from core.location.mobility import BasicRangeModel
 from core.services.utility import SshService
@@ -20,7 +20,8 @@ class TestXml:
         # create hook
         file_name = "runtime_hook.sh"
         data = "#!/bin/sh\necho hello"
-        session.set_hook("hook:4", file_name, None, data)
+        state = EventTypes.RUNTIME_STATE
+        session.add_hook(state, file_name, None, data)
 
         # save xml
         xml_file = tmpdir.join("session.xml")
@@ -38,7 +39,7 @@ class TestXml:
         session.open_xml(file_path, start=True)
 
         # verify nodes have been recreated
-        runtime_hooks = session._hooks.get(4)
+        runtime_hooks = session._hooks.get(state)
         assert runtime_hooks
         runtime_hook = runtime_hooks[0]
         assert file_name == runtime_hook[0]
@@ -269,7 +270,7 @@ class TestXml:
         switch_two = session.get_node(n2_id)
         assert switch_one
         assert switch_two
-        assert len(switch_one.all_link_data(0) + switch_two.all_link_data(0)) == 1
+        assert len(switch_one.all_link_data() + switch_two.all_link_data()) == 1
 
     def test_link_options(self, session, tmpdir, ip_prefixes):
         """
@@ -329,7 +330,7 @@ class TestXml:
         links = []
         for node_id in session.nodes:
             node = session.nodes[node_id]
-            links += node.all_link_data(0)
+            links += node.all_link_data()
         link = links[0]
         assert link_options.per == link.per
         assert link_options.bandwidth == link.bandwidth
@@ -396,7 +397,7 @@ class TestXml:
         links = []
         for node_id in session.nodes:
             node = session.nodes[node_id]
-            links += node.all_link_data(0)
+            links += node.all_link_data()
         link = links[0]
         assert link_options.per == link.per
         assert link_options.bandwidth == link.bandwidth
@@ -478,7 +479,7 @@ class TestXml:
         links = []
         for node_id in session.nodes:
             node = session.nodes[node_id]
-            links += node.all_link_data(0)
+            links += node.all_link_data()
         assert len(links) == 2
         link_one = links[0]
         link_two = links[1]