diff --git a/ReClass.NET/Constants.cs b/ReClass.NET/Constants.cs
index 4e54782a..bd918dbe 100644
--- a/ReClass.NET/Constants.cs
+++ b/ReClass.NET/Constants.cs
@@ -1,4 +1,4 @@
-namespace ReClassNET
+namespace ReClassNET
 {
 	public class Constants
 	{
@@ -39,5 +39,14 @@ public static class CommandLineOptions
 			public const string FileExtRegister = "registerfileext";
 			public const string FileExtUnregister = "unregisterfileext";
 		}
+
+		/// <summary>
+		/// Change type for commandified members in classes which is used to signal what change occurred exactly. As we don't use this feature of the commandified
+		/// class, this enum is defined to simply signal 'no specific change other than it changed' happened. 
+		/// </summary>
+		public enum GeneralPurposeChangeType
+		{
+			None
+		}
 	}
 }
diff --git a/ReClass.NET/Controls/MemoryViewControl.cs b/ReClass.NET/Controls/MemoryViewControl.cs
index 64b8dfa4..d323903b 100644
--- a/ReClass.NET/Controls/MemoryViewControl.cs
+++ b/ReClass.NET/Controls/MemoryViewControl.cs
@@ -704,5 +704,23 @@ public void Reset()
 
 			VerticalScroll.Value = VerticalScroll.Minimum;
 		}
+		
+		public void InitCurrentClassFromRTTI(ClassNode classNode)
+		{
+			var args = new DrawContextRequestEventArgs { Node = classNode };
+
+			var requestHandler = DrawContextRequested;
+			requestHandler?.Invoke(this, args);
+			var view = new DrawContext
+					   {
+						   Settings = args.Settings,
+						   Process = args.Process,
+						   Memory = args.Memory,
+						   CurrentTime = args.CurrentTime,
+						   Address = args.BaseAddress,
+						   Level = 0,
+					   };
+			classNode.InitFromRTTI(view);
+		}
 	}
 }
diff --git a/ReClass.NET/Forms/MainForm.Designer.cs b/ReClass.NET/Forms/MainForm.Designer.cs
index e2b2a199..20b2c907 100644
--- a/ReClass.NET/Forms/MainForm.Designer.cs
+++ b/ReClass.NET/Forms/MainForm.Designer.cs
@@ -77,6 +77,7 @@ private void InitializeComponent()
 			this.toolStripSeparator8 = new System.Windows.Forms.ToolStripSeparator();
 			this.createClassFromNodesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
 			this.toolStripSeparator13 = new System.Windows.Forms.ToolStripSeparator();
+			this.initClassToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
 			this.dissectNodesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
 			this.toolStripSeparator9 = new System.Windows.Forms.ToolStripSeparator();
 			this.searchForEqualValuesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
@@ -106,6 +107,7 @@ private void InitializeComponent()
 			this.saveToolStripButton = new System.Windows.Forms.ToolStripButton();
 			this.toolStripSeparator7 = new System.Windows.Forms.ToolStripSeparator();
 			this.newClassToolStripButton = new System.Windows.Forms.ToolStripButton();
+			this.initClassFromRTTIToolStripBarMenuItem = new ReClassNET.Controls.TypeToolStripMenuItem();
 			this.addBytesToolStripDropDownButton = new System.Windows.Forms.ToolStripDropDownButton();
 			this.add4BytesToolStripMenuItem = new ReClassNET.Controls.IntegerToolStripMenuItem();
 			this.add8BytesToolStripMenuItem = new ReClassNET.Controls.IntegerToolStripMenuItem();
@@ -167,6 +169,8 @@ private void InitializeComponent()
 			this.generateCSharpCodeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
 			this.helpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
 			this.aboutToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+			this.undoToolbarMenuItem = new ReClassNET.Controls.TypeToolStripMenuItem();
+			this.redoToolbarMenuItem = new ReClassNET.Controls.TypeToolStripMenuItem();
 			((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit();
 			this.splitContainer.Panel1.SuspendLayout();
 			this.splitContainer.Panel2.SuspendLayout();
@@ -202,7 +206,7 @@ private void InitializeComponent()
 			// 
 			this.splitContainer.Panel2.BackColor = System.Drawing.SystemColors.Control;
 			this.splitContainer.Panel2.Controls.Add(this.memoryViewControl);
-			this.splitContainer.Size = new System.Drawing.Size(1141, 524);
+			this.splitContainer.Size = new System.Drawing.Size(1103, 524);
 			this.splitContainer.SplitterDistance = 201;
 			this.splitContainer.TabIndex = 4;
 			// 
@@ -364,7 +368,7 @@ private void InitializeComponent()
 			this.memoryViewControl.Location = new System.Drawing.Point(0, 0);
 			this.memoryViewControl.Name = "memoryViewControl";
 			this.memoryViewControl.NodeContextMenuStrip = this.selectedNodeContextMenuStrip;
-			this.memoryViewControl.Size = new System.Drawing.Size(936, 524);
+			this.memoryViewControl.Size = new System.Drawing.Size(898, 524);
 			this.memoryViewControl.TabIndex = 0;
 			this.memoryViewControl.DrawContextRequested += new ReClassNET.Controls.DrawContextRequestEventHandler(this.memoryViewControl_DrawContextRequested);
 			this.memoryViewControl.SelectionChanged += new System.EventHandler(this.memoryViewControl_SelectionChanged);
@@ -382,6 +386,7 @@ private void InitializeComponent()
             this.toolStripSeparator8,
             this.createClassFromNodesToolStripMenuItem,
             this.toolStripSeparator13,
+            this.initClassToolStripMenuItem,
             this.dissectNodesToolStripMenuItem,
             this.toolStripSeparator9,
             this.searchForEqualValuesToolStripMenuItem,
@@ -402,7 +407,7 @@ private void InitializeComponent()
             this.showCodeOfClassToolStripMenuItem,
             this.shrinkClassToolStripMenuItem});
 			this.selectedNodeContextMenuStrip.Name = "selectedNodeContextMenuStrip";
-			this.selectedNodeContextMenuStrip.Size = new System.Drawing.Size(270, 410);
+			this.selectedNodeContextMenuStrip.Size = new System.Drawing.Size(270, 432);
 			this.selectedNodeContextMenuStrip.Opening += new System.ComponentModel.CancelEventHandler(this.selectedNodeContextMenuStrip_Opening);
 			// 
 			// changeTypeToolStripMenuItem
@@ -604,6 +609,16 @@ private void InitializeComponent()
 			this.toolStripSeparator13.Name = "toolStripSeparator13";
 			this.toolStripSeparator13.Size = new System.Drawing.Size(266, 6);
 			// 
+			// initClassToolStripMenuItem
+			// 
+			this.initClassToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Button_AutoName;
+			this.initClassToolStripMenuItem.Name = "initClassToolStripMenuItem";
+			this.initClassToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)(((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Shift) 
+            | System.Windows.Forms.Keys.N)));
+			this.initClassToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
+			this.initClassToolStripMenuItem.Text = "Init Class from RTTI";
+			this.initClassToolStripMenuItem.Click += new System.EventHandler(this.initClassToolStripMenuItem_Click);
+			// 
 			// dissectNodesToolStripMenuItem
 			// 
 			this.dissectNodesToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Camera;
@@ -771,12 +786,15 @@ private void InitializeComponent()
             this.saveToolStripButton,
             this.toolStripSeparator7,
             this.newClassToolStripButton,
+            this.initClassFromRTTIToolStripBarMenuItem,
             this.addBytesToolStripDropDownButton,
             this.insertBytesToolStripDropDownButton,
-            this.nodeTypesToolStripSeparator});
+            this.nodeTypesToolStripSeparator,
+            this.undoToolbarMenuItem,
+            this.redoToolbarMenuItem});
 			this.toolStrip.Location = new System.Drawing.Point(0, 24);
 			this.toolStrip.Name = "toolStrip";
-			this.toolStrip.Size = new System.Drawing.Size(1141, 25);
+			this.toolStrip.Size = new System.Drawing.Size(1103, 25);
 			this.toolStrip.TabIndex = 3;
 			// 
 			// attachToProcessToolStripSplitButton
@@ -832,6 +850,19 @@ private void InitializeComponent()
 			this.newClassToolStripButton.ToolTipText = "Add a new class to this project";
 			this.newClassToolStripButton.Click += new System.EventHandler(this.newClassToolStripButton_Click);
 			// 
+			// initClassFromRTTIToolStripBarMenuItem
+			// 
+			this.initClassFromRTTIToolStripBarMenuItem.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
+			this.initClassFromRTTIToolStripBarMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Button_AutoName;
+			this.initClassFromRTTIToolStripBarMenuItem.Name = "initClassFromRTTIToolStripBarMenuItem";
+			this.initClassFromRTTIToolStripBarMenuItem.Overflow = System.Windows.Forms.ToolStripItemOverflow.AsNeeded;
+			this.initClassFromRTTIToolStripBarMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)(((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Shift) 
+            | System.Windows.Forms.Keys.N)));
+			this.initClassFromRTTIToolStripBarMenuItem.Size = new System.Drawing.Size(28, 25);
+			this.initClassFromRTTIToolStripBarMenuItem.ToolTipText = "Init selected class from RTTI info";
+			this.initClassFromRTTIToolStripBarMenuItem.Value = null;
+			this.initClassFromRTTIToolStripBarMenuItem.Click += new System.EventHandler(this.initClassToolStripMenuItem_Click);
+			// 
 			// addBytesToolStripDropDownButton
 			// 
 			this.addBytesToolStripDropDownButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
@@ -1023,7 +1054,7 @@ private void InitializeComponent()
             this.infoToolStripStatusLabel});
 			this.statusStrip.Location = new System.Drawing.Point(0, 573);
 			this.statusStrip.Name = "statusStrip";
-			this.statusStrip.Size = new System.Drawing.Size(1141, 22);
+			this.statusStrip.Size = new System.Drawing.Size(1103, 22);
 			this.statusStrip.TabIndex = 1;
 			// 
 			// processInfoToolStripStatusLabel
@@ -1048,7 +1079,7 @@ private void InitializeComponent()
             this.helpToolStripMenuItem});
 			this.mainMenuStrip.Location = new System.Drawing.Point(0, 0);
 			this.mainMenuStrip.Name = "mainMenuStrip";
-			this.mainMenuStrip.Size = new System.Drawing.Size(1141, 24);
+			this.mainMenuStrip.Size = new System.Drawing.Size(1103, 24);
 			this.mainMenuStrip.TabIndex = 2;
 			// 
 			// fileToolStripMenuItem
@@ -1367,16 +1398,37 @@ private void InitializeComponent()
 			this.aboutToolStripMenuItem.Text = "About...";
 			this.aboutToolStripMenuItem.Click += new System.EventHandler(this.aboutToolStripMenuItem_Click);
 			// 
+			// undoToolbarMenuItem
+			// 
+			this.undoToolbarMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Undo;
+			this.undoToolbarMenuItem.Name = "undoToolbarMenuItem";
+			this.undoToolbarMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Z)));
+			this.undoToolbarMenuItem.Size = new System.Drawing.Size(28, 25);
+			this.undoToolbarMenuItem.ToolTipText = "Undo the latest change";
+			this.undoToolbarMenuItem.Value = null;
+			this.undoToolbarMenuItem.Click += new System.EventHandler(this.undoToolbarMenuItem_Click);
+			// 
+			// redoToolbarMenuItem
+			// 
+			this.redoToolbarMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Redo;
+			this.redoToolbarMenuItem.Name = "redoToolbarMenuItem";
+			this.redoToolbarMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Y)));
+			this.redoToolbarMenuItem.Size = new System.Drawing.Size(28, 25);
+			this.redoToolbarMenuItem.ToolTipText = "Redo the latest undone change";
+			this.redoToolbarMenuItem.Value = null;
+			this.redoToolbarMenuItem.Click += new System.EventHandler(this.redoToolbarMenuItem_Click);
+			// 
 			// MainForm
 			// 
 			this.AllowDrop = true;
 			this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
 			this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
-			this.ClientSize = new System.Drawing.Size(1141, 595);
+			this.ClientSize = new System.Drawing.Size(1103, 595);
 			this.Controls.Add(this.splitContainer);
 			this.Controls.Add(this.toolStrip);
 			this.Controls.Add(this.statusStrip);
 			this.Controls.Add(this.mainMenuStrip);
+			this.KeyPreview = true;
 			this.MainMenuStrip = this.mainMenuStrip;
 			this.MinimumSize = new System.Drawing.Size(200, 100);
 			this.Name = "MainForm";
@@ -1542,6 +1594,10 @@ private void InitializeComponent()
 		private System.Windows.Forms.ToolStripMenuItem showEnumsToolStripMenuItem;
 		private System.Windows.Forms.ToolStripSeparator toolStripSeparator23;
 		private System.Windows.Forms.ToolStripMenuItem isLittleEndianToolStripMenuItem;
+		private System.Windows.Forms.ToolStripMenuItem initClassToolStripMenuItem;
+		private TypeToolStripMenuItem initClassFromRTTIToolStripBarMenuItem;
+		private TypeToolStripMenuItem undoToolbarMenuItem;
+		private TypeToolStripMenuItem redoToolbarMenuItem;
 	}
 }
 
diff --git a/ReClass.NET/Forms/MainForm.Functions.cs b/ReClass.NET/Forms/MainForm.Functions.cs
index 84f1b53a..d5eaeeab 100644
--- a/ReClass.NET/Forms/MainForm.Functions.cs
+++ b/ReClass.NET/Forms/MainForm.Functions.cs
@@ -16,6 +16,7 @@
 using ReClassNET.Nodes;
 using ReClassNET.Project;
 using ReClassNET.UI;
+using SD.Tools.Algorithmia.Commands;
 
 namespace ReClassNET.Forms
 {
@@ -213,6 +214,10 @@ public void LoadProjectFromPath(string path)
 		{
 			Contract.Requires(path != null);
 
+			CommandQueueManagerSingleton.GetInstance().ResetActiveCommandQueue();
+			CommandQueueManagerSingleton.GetInstance().BeginNonUndoablePeriod();		// we don't want to trigger undo/redo activity while loading
+			CommandQueueManagerSingleton.GetInstance().RaiseEvents = false;
+
 			var project = new ReClassNetProject();
 
 			LoadProjectFromPath(path, ref project);
@@ -224,6 +229,10 @@ public void LoadProjectFromPath(string path)
 			}
 
 			SetProject(project);
+
+			// Done loading, resume undo/redo activity
+			CommandQueueManagerSingleton.GetInstance().RaiseEvents = true;
+			CommandQueueManagerSingleton.GetInstance().EndNonUndoablePeriod();
 		}
 
 		/// <summary>Loads the file into the given project.</summary>
@@ -310,6 +319,9 @@ public void ReplaceSelectedNodesWithType(Type type)
 					{
 						var selected = hotSpotsToReplace.Dequeue();
 
+						// Use a single command here to wrap all state changes into one single undoable object, so everything gets undone/redone in 1 go
+						var cmd = new UndoablePeriodCommand("Replace node");
+						CommandQueueManagerSingleton.GetInstance().BeginUndoablePeriod(cmd);
 						var node = BaseNode.CreateInstanceFromType(type);
 
 						var createdNodes = new List<BaseNode>();
@@ -329,6 +341,8 @@ public void ReplaceSelectedNodesWithType(Type type)
 								hotSpotsToReplace.Enqueue(new MemoryViewControl.SelectedNodeInfo(createdNode, selected.Process, selected.Memory, selected.Address + createdNode.Offset - node.Offset, selected.Level));
 							}
 						}
+						// Mark the end of the activities that have to be tracked with this single command
+						CommandQueueManagerSingleton.GetInstance().EndUndoablePeriod(cmd);
 					}
 				}
 
diff --git a/ReClass.NET/Forms/MainForm.cs b/ReClass.NET/Forms/MainForm.cs
index e771a10d..53b1c8db 100644
--- a/ReClass.NET/Forms/MainForm.cs
+++ b/ReClass.NET/Forms/MainForm.cs
@@ -22,6 +22,7 @@
 using ReClassNET.UI;
 using ReClassNET.Util;
 using ReClassNET.Util.Conversion;
+using SD.Tools.Algorithmia.Commands;
 
 namespace ReClassNET.Forms
 {
@@ -95,8 +96,11 @@ public MainForm()
 			};
 
 			pluginManager = new PluginManager(new DefaultPluginHost(this, Program.RemoteProcess, Program.Logger));
+
+			CommandQueueManagerSingleton.GetInstance().CommandQueueActionPerformed += OnCommandQueueActionPerformed;
 		}
 
+
 		protected override void OnLoad(EventArgs e)
 		{
 			base.OnLoad(e);
@@ -135,6 +139,8 @@ protected override void OnLoad(EventArgs e)
 			{
 				AttachToProcess(Program.CommandLineArgs[Constants.CommandLineOptions.AttachTo]);
 			}
+
+			SetStateOfUndoRedoButtons();
 		}
 
 		protected override void OnFormClosed(FormClosedEventArgs e)
@@ -835,6 +841,8 @@ private void memoryViewControl_SelectionChanged(object sender, EventArgs e)
 
 			addBytesToolStripDropDownButton.Enabled = parentContainer != null || isContainerNode;
 			insertBytesToolStripDropDownButton.Enabled = selectedNodes.Count == 1 && parentContainer != null && !isContainerNode;
+			initClassToolStripMenuItem.Enabled = nodeIsClass;
+			initClassFromRTTIToolStripBarMenuItem.Enabled = nodeIsClass;
 
 			var enabled = selectedNodes.Count > 0 && !nodeIsClass;
 			toolStrip.Items.OfType<TypeToolStripButton>().ForEach(b => b.Enabled = enabled);
@@ -1027,7 +1035,7 @@ private void memoryViewControl_DrawContextRequested(object sender, DrawContextRe
 		{
 			var process = Program.RemoteProcess;
 
-			var classNode = CurrentClassNode;
+			var classNode = (args.Node as ClassNode) ?? CurrentClassNode;
 			if (classNode != null)
 			{
 				memoryViewBuffer.Size = classNode.MemorySize;
@@ -1051,5 +1059,45 @@ private void memoryViewControl_DrawContextRequested(object sender, DrawContextRe
 				args.BaseAddress = address;
 			}
 		}
+		
+		private void initClassToolStripMenuItem_Click(object sender, EventArgs e)
+		{
+			var selectedNodes = memoryViewControl.GetSelectedNodes();
+			var node = selectedNodes.FirstOrDefault()?.Node;
+			if (node == null || !(node is ClassNode))
+			{
+				return;
+			}
+
+			var cmd = new UndoablePeriodCommand("InitClassFromRTTI");
+			CommandQueueManagerSingleton.GetInstance().BeginUndoablePeriod(cmd);
+			memoryViewControl.InitCurrentClassFromRTTI(node as ClassNode);
+			CommandQueueManagerSingleton.GetInstance().EndUndoablePeriod(cmd);
+		}
+
+
+		private void SetStateOfUndoRedoButtons()
+		{
+			undoToolbarMenuItem.Enabled = CommandQueueManagerSingleton.GetInstance().CanUndo(Program.CommandQueueID);
+			redoToolbarMenuItem.Enabled = CommandQueueManagerSingleton.GetInstance().CanDo(Program.CommandQueueID);
+		}
+
+
+		private void OnCommandQueueActionPerformed(object sender, CommandQueueActionPerformedEventArgs e)
+		{
+			SetStateOfUndoRedoButtons();
+		}
+
+
+		private void undoToolbarMenuItem_Click(object sender, EventArgs e)
+		{
+			CommandQueueManagerSingleton.GetInstance().UndoLastCommand();
+		}
+
+
+		private void redoToolbarMenuItem_Click(object sender, EventArgs e)
+		{
+			CommandQueueManagerSingleton.GetInstance().RedoLastCommand();
+		}
 	}
 }
diff --git a/ReClass.NET/Forms/MainForm.resx b/ReClass.NET/Forms/MainForm.resx
index c430dab3..0e88c503 100644
--- a/ReClass.NET/Forms/MainForm.resx
+++ b/ReClass.NET/Forms/MainForm.resx
@@ -206,6 +206,6 @@
 </value>
   </data>
   <metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
-    <value>42</value>
+    <value>104</value>
   </metadata>
 </root>
\ No newline at end of file
diff --git a/ReClass.NET/Memory/MemoryBuffer.cs b/ReClass.NET/Memory/MemoryBuffer.cs
index e1b515a4..cb7361ec 100644
--- a/ReClass.NET/Memory/MemoryBuffer.cs
+++ b/ReClass.NET/Memory/MemoryBuffer.cs
@@ -366,5 +366,17 @@ public bool HasChanged(int offset, int length)
 
 			return false;
 		}
+		
+		public UInt64FloatDoubleData InterpretData64(int offset) => new UInt64FloatDoubleData
+																   {
+																	   Raw1 = ReadInt32(offset),
+																	   Raw2 = ReadInt32(offset + sizeof(int))
+																   };
+
+
+		public UInt32FloatData InterpretData32(int offset) => new UInt32FloatData
+															 {
+																 Raw = ReadInt32(offset)
+															 };
 	}
 }
diff --git a/ReClass.NET/Nodes/BaseContainerNode.cs b/ReClass.NET/Nodes/BaseContainerNode.cs
index 6926111f..1d3ec5e8 100644
--- a/ReClass.NET/Nodes/BaseContainerNode.cs
+++ b/ReClass.NET/Nodes/BaseContainerNode.cs
@@ -1,12 +1,16 @@
-using System;
+using System;
 using System.Collections.Generic;
 using System.Diagnostics.Contracts;
+using ReClassNET.Extensions;
+using SD.Tools.Algorithmia.Commands;
+using SD.Tools.Algorithmia.GeneralDataStructures;
 
 namespace ReClassNET.Nodes
 {
 	public abstract class BaseContainerNode : BaseNode
 	{
-		private readonly List<BaseNode> nodes = new List<BaseNode>();
+		//private readonly List<BaseNode> nodes = new List<BaseNode>();
+		private readonly CommandifiedList<BaseNode> nodes = new CommandifiedList<BaseNode>();
 
 		private int updateCount;
 
@@ -183,8 +187,8 @@ public void ReplaceChildNode(BaseNode oldNode, BaseNode newNode, ref List<BaseNo
 			}
 
 			newNode.CopyFromNode(oldNode);
-
 			newNode.ParentNode = this;
+			newNode.PerformPostInitWork();
 
 			nodes[index] = newNode;
 
@@ -262,7 +266,8 @@ protected void InsertBytes(int index, int size, ref List<BaseNode> createdNodes)
 			{
 				return;
 			}
-
+			// Mark the actions that follow as actions that have to be ignored so they're not ending up in a command's command queue
+			CommandQueueManagerSingleton.GetInstance().BeginNonUndoablePeriod();
 			while (size > 0)
 			{
 				var node = CreateDefaultNodeForSize(size);
@@ -281,6 +286,8 @@ protected void InsertBytes(int index, int size, ref List<BaseNode> createdNodes)
 
 				index++;
 			}
+			// Mark the end of the actions that have to be ignored for undo/redo
+			CommandQueueManagerSingleton.GetInstance().EndNonUndoablePeriod();
 
 			OnNodesUpdated();
 		}
diff --git a/ReClass.NET/Nodes/BaseHexCommentNode.cs b/ReClass.NET/Nodes/BaseHexCommentNode.cs
index f2a4053f..98305d8c 100644
--- a/ReClass.NET/Nodes/BaseHexCommentNode.cs
+++ b/ReClass.NET/Nodes/BaseHexCommentNode.cs
@@ -44,7 +44,7 @@ protected int AddComment(DrawContext view, int x, int y, float fvalue, IntPtr iv
 
 					if (view.Settings.ShowCommentRtti)
 					{
-						var rtti = view.Process.ReadRemoteRuntimeTypeInformation(ivalue);
+						var rtti = GetAssociatedRemoteRuntimeTypeInformation(view, ivalue);
 						if (!string.IsNullOrEmpty(rtti))
 						{
 							x = AddText(view, x, y, view.Settings.OffsetColor, HotSpot.ReadOnlyId, rtti) + view.Font.Width;
@@ -110,5 +110,10 @@ protected int AddComment(DrawContext view, int x, int y, float fvalue, IntPtr iv
 
 			return x;
 		}
+
+		public string GetAssociatedRemoteRuntimeTypeInformation(DrawContext context, IntPtr ivalue)
+		{
+			return context.Process.ReadRemoteRuntimeTypeInformation(ivalue);
+		}
 	}
 }
diff --git a/ReClass.NET/Nodes/BaseNode.cs b/ReClass.NET/Nodes/BaseNode.cs
index adef39e5..edac2e11 100644
--- a/ReClass.NET/Nodes/BaseNode.cs
+++ b/ReClass.NET/Nodes/BaseNode.cs
@@ -7,6 +7,8 @@
 using ReClassNET.Extensions;
 using ReClassNET.UI;
 using ReClassNET.Util;
+using SD.Tools.Algorithmia.GeneralDataStructures;
+using SD.Tools.Algorithmia.GeneralDataStructures.EventArguments;
 
 namespace ReClassNET.Nodes
 {
@@ -24,14 +26,25 @@ public abstract class BaseNode
 
 		private static int nodeIndex = 0;
 
-		private string name = string.Empty;
+		private CommandifiedMember<string, Constants.GeneralPurposeChangeType> name;
 		private string comment = string.Empty;
 
 		/// <summary>Gets or sets the offset of the node.</summary>
 		public int Offset { get; set; }
 
 		/// <summary>Gets or sets the name of the node. If a new name was set the property changed event gets fired.</summary>
-		public virtual string Name { get => name; set { if (value != null && name != value) { name = value; NameChanged?.Invoke(this); } } }
+		public virtual string Name
+		{
+			get => name.MemberValue;
+			set
+			{
+				if (value == null)
+				{
+					return;
+				}
+				name.MemberValue = value;
+			}
+		}
 
 		/// <summary>Gets or sets the comment of the node.</summary>
 		public string Comment { get => comment; set { if (value != null && comment != value) { comment = value; CommentChanged?.Invoke(this); } } }
@@ -39,9 +52,12 @@ public abstract class BaseNode
 		/// <summary>Gets or sets the parent node.</summary>
 		public BaseNode ParentNode { get; internal set; }
 
-		/// <summary>Gets a value indicating whether this node is wrapped into an other node.</summary>
+		/// <summary>Gets a value indicating whether this node is wrapped into an other node. </summary>
 		public bool IsWrapped => ParentNode is BaseWrapperNode;
 
+		/// <summary>All nodes that are wrapped can't be selected except classnodes because they have a context menu</summary>
+		public bool CanBeSelected => !IsWrapped || (this is ClassNode);
+
 		/// <summary>Gets or sets a value indicating whether this node is hidden.</summary>
 		public bool IsHidden { get; set; }
 
@@ -97,12 +113,15 @@ protected BaseNode()
 			Contract.Ensures(name != null);
 			Contract.Ensures(comment != null);
 
-			Name = $"N{nodeIndex++:X08}";
+			name = new CommandifiedMember<string, Constants.GeneralPurposeChangeType>("Name", Constants.GeneralPurposeChangeType.None, $"N{nodeIndex++:X08}");
+			name.ValueChanged += Name_ValueChanged;
 			Comment = string.Empty;
 
 			LevelsOpen[0] = true;
 		}
 
+		private void Name_ValueChanged(object sender, MemberChangedEventArgs<Constants.GeneralPurposeChangeType, string> e) => NameChanged?.Invoke(this);
+
 		public abstract void GetUserInterfaceInfo(out string name, out Image icon);
 
 		public virtual bool UseMemoryPreviewToolTip(HotSpot spot, out IntPtr address)
@@ -236,6 +255,15 @@ public virtual void ClearSelection()
 		/// <returns>The calculated height.</returns>
 		public abstract int CalculateDrawnHeight(DrawContext context);
 
+		/// <summary>
+		/// Called when this node has been created, initialized and the parent node has been assigned. For some nodes
+		/// Additional work has to be performed, this work can be done in a derived method of this method.
+		/// </summary>
+		public virtual void PerformPostInitWork()
+		{
+			// nop
+		}
+
 		/// <summary>Updates the node from the given <paramref name="spot"/>. Sets the <see cref="Name"/> and <see cref="Comment"/> of the node.</summary>
 		/// <param name="spot">The spot.</param>
 		public virtual void Update(HotSpot spot)
@@ -367,7 +395,7 @@ protected void AddSelection(DrawContext context, int x, int y, int height)
 			Contract.Requires(context != null);
 			Contract.Requires(context.Graphics != null);
 
-			if (y > context.ClientArea.Bottom || y + height < 0 || IsWrapped)
+			if (y > context.ClientArea.Bottom || y + height < 0 || !CanBeSelected)
 			{
 				return;
 			}
diff --git a/ReClass.NET/Nodes/ClassNode.cs b/ReClass.NET/Nodes/ClassNode.cs
index 9b144061..d5eba916 100644
--- a/ReClass.NET/Nodes/ClassNode.cs
+++ b/ReClass.NET/Nodes/ClassNode.cs
@@ -1,9 +1,12 @@
 using System;
+using System.Collections.Generic;
 using System.Diagnostics.Contracts;
 using System.Drawing;
 using System.Linq;
 using ReClassNET.Controls;
 using ReClassNET.UI;
+using SD.Tools.Algorithmia.GeneralDataStructures;
+using SD.Tools.Algorithmia.GeneralDataStructures.EventArguments;
 
 namespace ReClassNET.Nodes
 {
@@ -27,7 +30,12 @@ public class ClassNode : BaseContainerNode
 
 		public Guid Uuid { get; set; }
 
-		public string AddressFormula { get; set; } = DefaultAddressFormula;
+		private CommandifiedMember<string, Constants.GeneralPurposeChangeType> addressFormula;
+		public string AddressFormula
+		{
+			get => addressFormula.MemberValue;
+			set => addressFormula.MemberValue = value;
+		}
 
 		public event NodeEventHandler NodesChanged;
 
@@ -35,6 +43,7 @@ internal ClassNode(bool notifyClassCreated)
 		{
 			Contract.Ensures(AddressFormula != null);
 
+			addressFormula = new CommandifiedMember<string, Constants.GeneralPurposeChangeType>("AddressFormula", Constants.GeneralPurposeChangeType.None, DefaultAddressFormula);
 			LevelsOpen.DefaultValue = true;
 
 			Uuid = Guid.NewGuid();
@@ -51,7 +60,48 @@ public static ClassNode Create()
 
 			return new ClassNode(true);
 		}
+		
+		/// <summary>
+		/// Initializes the class' name and vtable node from RTTI information, if it's not set already 
+		/// </summary>
+		/// <param name="context"></param>
+		public void InitFromRTTI(DrawContext context)
+		{
+			// first node should be a VTable node or a hex64/32 node
+			if (Nodes.Count <= 0)
+			{
+				return;
+			}
+
+			var rttiInfoFromFirstNode = string.Empty;
+			var firstNode = Nodes[0];
+			if (firstNode is VirtualMethodTableNode vtableNode)
+			{
+				rttiInfoFromFirstNode = vtableNode.GetAssociatedRemoteRuntimeTypeInformation(context);
+			}
+			else if (firstNode is BaseHexCommentNode baseHexCommentNode)
+			{
+				// ask it as if it might point to a vtable
+				var value = context.Memory.InterpretData64(Offset);
+				rttiInfoFromFirstNode = baseHexCommentNode.GetAssociatedRemoteRuntimeTypeInformation(context, value.IntPtr);
+				if (!string.IsNullOrEmpty(rttiInfoFromFirstNode))
+				{
+					// convert first node to vtable node
+					var newVTableNode = BaseNode.CreateInstanceFromType(typeof(VirtualMethodTableNode));
+					var createdNodes = new List<BaseNode>();
+					this.ReplaceChildNode(firstNode, newVTableNode, ref createdNodes);
+				}
+			}
 
+			if (string.IsNullOrEmpty(rttiInfoFromFirstNode))
+			{
+				return;
+			}
+
+			var fragments = rttiInfoFromFirstNode.Split(':');
+			this.Name = fragments[0];
+		}
+		
 		public override void GetUserInterfaceInfo(out string name, out Image icon)
 		{
 			throw new InvalidOperationException($"The '{nameof(ClassNode)}' node should not be accessible from the ui.");
diff --git a/ReClass.NET/Nodes/Hex32Node.cs b/ReClass.NET/Nodes/Hex32Node.cs
index c7b54027..2329c954 100644
--- a/ReClass.NET/Nodes/Hex32Node.cs
+++ b/ReClass.NET/Nodes/Hex32Node.cs
@@ -18,7 +18,7 @@ public override void GetUserInterfaceInfo(out string name, out Image icon)
 
 		public override bool UseMemoryPreviewToolTip(HotSpot spot, out IntPtr address)
 		{
-			var value = ReadFromBuffer(spot.Memory, Offset);
+			var value = spot.Memory.InterpretData32(Offset);
 
 			address = value.IntPtr;
 
@@ -27,7 +27,7 @@ public override bool UseMemoryPreviewToolTip(HotSpot spot, out IntPtr address)
 
 		public override string GetToolTipText(HotSpot spot)
 		{
-			var value = ReadFromBuffer(spot.Memory, Offset);
+			var value = spot.Memory.InterpretData32(Offset);
 
 			return $"Int32: {value.IntValue}\nUInt32: 0x{value.UIntValue:X08}\nFloat: {value.FloatValue:0.000}";
 		}
@@ -46,16 +46,11 @@ protected override int AddComment(DrawContext context, int x, int y)
 		{
 			x = base.AddComment(context, x, y);
 
-			var value = ReadFromBuffer(context.Memory, Offset);
+			var value = context.Memory.InterpretData32(Offset);
 
 			x = AddComment(context, x, y, value.FloatValue, value.IntPtr, value.UIntPtr);
 
 			return x;
 		}
-
-		private static UInt32FloatData ReadFromBuffer(MemoryBuffer memory, int offset) => new UInt32FloatData
-		{
-			Raw = memory.ReadInt32(offset)
-		};
 	}
 }
diff --git a/ReClass.NET/Nodes/Hex64Node.cs b/ReClass.NET/Nodes/Hex64Node.cs
index d54f1e71..61749e46 100644
--- a/ReClass.NET/Nodes/Hex64Node.cs
+++ b/ReClass.NET/Nodes/Hex64Node.cs
@@ -18,7 +18,7 @@ public override void GetUserInterfaceInfo(out string name, out Image icon)
 
 		public override bool UseMemoryPreviewToolTip(HotSpot spot, out IntPtr address)
 		{
-			var value = ReadFromBuffer(spot.Memory, Offset);
+			var value = spot.Memory.InterpretData64(Offset);
 
 			address = value.IntPtr;
 
@@ -27,7 +27,7 @@ public override bool UseMemoryPreviewToolTip(HotSpot spot, out IntPtr address)
 
 		public override string GetToolTipText(HotSpot spot)
 		{
-			var value = ReadFromBuffer(spot.Memory, Offset);
+			var value = spot.Memory.InterpretData64(Offset);
 
 			return $"Int64: {value.LongValue}\nUInt64: 0x{value.ULongValue:X016}\nFloat: {value.FloatValue:0.000}\nDouble: {value.DoubleValue:0.000}";
 		}
@@ -46,17 +46,11 @@ protected override int AddComment(DrawContext context, int x, int y)
 		{
 			x = base.AddComment(context, x, y);
 
-			var value = ReadFromBuffer(context.Memory, Offset);
+			var value = context.Memory.InterpretData64(Offset);
 
 			x = AddComment(context, x, y, value.FloatValue, value.IntPtr, value.UIntPtr);
 
 			return x;
 		}
-
-		private static UInt64FloatDoubleData ReadFromBuffer(MemoryBuffer memory, int offset) => new UInt64FloatDoubleData
-		{
-			Raw1 = memory.ReadInt32(offset),
-			Raw2 = memory.ReadInt32(offset + sizeof(int))
-		};
 	}
 }
diff --git a/ReClass.NET/Nodes/PointerNode.cs b/ReClass.NET/Nodes/PointerNode.cs
index 027b0d28..9df3b8b0 100644
--- a/ReClass.NET/Nodes/PointerNode.cs
+++ b/ReClass.NET/Nodes/PointerNode.cs
@@ -1,5 +1,6 @@
 using System;
 using System.Drawing;
+using ReClassNET.AddressParser;
 using ReClassNET.Controls;
 using ReClassNET.Memory;
 using ReClassNET.UI;
@@ -134,5 +135,39 @@ public override int CalculateDrawnHeight(DrawContext context)
 			}
 			return height;
 		}
+		
+		public override void PerformPostInitWork()
+		{
+			base.PerformPostInitWork();
+
+			var parentClass = ParentNode as ClassNode;
+			if (parentClass == null)
+			{
+				return;
+			}
+
+			var process = Program.RemoteProcess;
+			IntPtr address;
+			try
+			{
+				address = process.ParseAddress(parentClass.AddressFormula);
+			}
+			catch (ParseException)
+			{
+				address = IntPtr.Zero;
+			}
+
+			var memoryBuffer = new MemoryBuffer() { Size = parentClass.MemorySize};
+			memoryBuffer.UpdateFrom(process, address);
+			var ptr = memoryBuffer.ReadIntPtr(Offset);
+
+			var classNode = ((ClassInstanceNode)InnerNode)?.InnerNode as ClassNode;
+			if (classNode == null)
+			{
+				return;
+			}
+
+			classNode.AddressFormula = ptr.ToString(Constants.AddressHexFormat);
+		}
 	}
 }
diff --git a/ReClass.NET/Nodes/VirtualMethodTableNode.cs b/ReClass.NET/Nodes/VirtualMethodTableNode.cs
index 9e82ab40..2c9099a0 100644
--- a/ReClass.NET/Nodes/VirtualMethodTableNode.cs
+++ b/ReClass.NET/Nodes/VirtualMethodTableNode.cs
@@ -33,7 +33,33 @@ public override void Initialize()
 				AddNode(CreateDefaultNodeForSize(IntPtr.Size));
 			}
 		}
+		
+		protected override int AddComment(DrawContext context, int x, int y)
+		{
+			x = base.AddComment(context, x, y);
+			
+			if (context.Settings.ShowCommentRtti)
+			{
+				var rtti = GetAssociatedRemoteRuntimeTypeInformation(context);
+				if (!string.IsNullOrEmpty(rtti))
+				{
+					x = AddText(context, x, y, context.Settings.OffsetColor, HotSpot.ReadOnlyId, rtti) + context.Font.Width;
+				}
+			}
+			return x;
+		}
+		
+		public string GetAssociatedRemoteRuntimeTypeInformation(DrawContext context)
+		{
+			var addressFirstVTableFunction = context.Memory.InterpretData64(Offset).IntPtr;
+			if (addressFirstVTableFunction != IntPtr.Zero)
+			{
+				return context.Process.ReadRemoteRuntimeTypeInformation(addressFirstVTableFunction);
+			}
 
+			return string.Empty;
+		}
+		
 		public override Size Draw(DrawContext context, int x, int y)
 		{
 			if (IsHidden && !IsWrapped)
diff --git a/ReClass.NET/Program.cs b/ReClass.NET/Program.cs
index f28cb0bd..aba0f3f1 100644
--- a/ReClass.NET/Program.cs
+++ b/ReClass.NET/Program.cs
@@ -2,6 +2,7 @@
 using System.Diagnostics;
 using System.Drawing;
 using System.Globalization;
+using System.Threading;
 using System.Windows.Forms;
 using Microsoft.SqlServer.MessageBox;
 using ReClassNET.Core;
@@ -11,6 +12,7 @@
 using ReClassNET.Native;
 using ReClassNET.UI;
 using ReClassNET.Util;
+using SD.Tools.Algorithmia.Commands;
 
 namespace ReClassNET
 {
@@ -34,10 +36,18 @@ public static class Program
 
 		public static FontEx MonoSpaceFont { get; private set; }
 
+		public static Guid CommandQueueID { get; private set; }
+
 		[STAThread]
 		static void Main(string[] args)
 		{
 			DesignMode = false; // The designer doesn't call Main()
+			CommandQueueID = Guid.NewGuid();
+
+			// wire event handlers for unhandled exceptions, so these will be shown using our own method.
+			Application.SetUnhandledExceptionMode(UnhandledExceptionMode.Automatic, true);
+			Application.ThreadException += new ThreadExceptionEventHandler(Program.Application_ThreadException);
+			AppDomain.CurrentDomain.UnhandledException+=new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
 
 			CommandLineArgs = new CommandLineArgs(args);
 
@@ -63,6 +73,11 @@ static void Main(string[] args)
 			Application.EnableVisualStyles();
 			Application.SetCompatibleTextRenderingDefault(false);
 
+			// switch is set to false, so Do actions during Undo actions are ignored.
+			CommandQueueManager.ThrowExceptionOnDoDuringUndo = false;
+			// activate our command queue stack. We're only changing things from the main thread so we don't need multiple stacks.
+			CommandQueueManagerSingleton.GetInstance().ActivateCommandQueueStack(CommandQueueID);
+
 			CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture;
 
 			Settings = SettingsSerializer.Load();
@@ -98,7 +113,17 @@ static void Main(string[] args)
 
 			SettingsSerializer.Save(Settings);
 		}
-
+		
+		private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
+		{
+			ShowException(e.Exception);
+		}
+		
+		private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
+		{
+			ShowException(e.ExceptionObject as Exception);
+		}
+		
 		/// <summary>Shows the exception in a special form.</summary>
 		/// <param name="ex">The exception.</param>
 		public static void ShowException(Exception ex)
diff --git a/ReClass.NET/Project/ReClassNetProject.cs b/ReClass.NET/Project/ReClassNetProject.cs
index 90f4b5ca..bd2be84b 100644
--- a/ReClass.NET/Project/ReClassNetProject.cs
+++ b/ReClass.NET/Project/ReClassNetProject.cs
@@ -1,9 +1,13 @@
 using System;
 using System.Collections.Generic;
+using System.ComponentModel;
 using System.Diagnostics.Contracts;
 using System.Linq;
+using ReClassNET.Extensions;
 using ReClassNET.Nodes;
 using ReClassNET.Util;
+using SD.Tools.Algorithmia.GeneralDataStructures;
+using SD.Tools.Algorithmia.GeneralDataStructures.EventArguments;
 
 namespace ReClassNET.Project
 {
@@ -18,7 +22,7 @@ public class ReClassNetProject : IDisposable
 		public event EnumsChangedEvent EnumRemoved;
 
 		private readonly List<EnumDescription> enums = new List<EnumDescription>();
-		private readonly List<ClassNode> classes = new List<ClassNode>();
+		private readonly CommandifiedList<ClassNode> classes = new CommandifiedList<ClassNode>();		// use a commandified list for the set of classes so we get auto undo/redo tracking
 
 		public IReadOnlyList<EnumDescription> Enums => enums;
 
@@ -36,6 +40,25 @@ public class ReClassNetProject : IDisposable
 		/// List of data types to use while generating C++ code for nodes.
 		/// </summary>
 		public CppTypeMapping TypeMapping { get; } = new CppTypeMapping();
+		
+		public ReClassNetProject()
+		{
+			// We're using ListChanged instead of ElementAdding here because ListChanged is also raised when 'Redo' is executed on the list re-adding the already created element.
+			classes.ListChanged += Classes_ListChanged;
+			classes.ElementRemoved += Classes_ElementRemoved;
+		}
+
+		private void Classes_ListChanged(object sender, System.ComponentModel.ListChangedEventArgs e)
+		{
+			// nothing. The removed event is handled separately because ListChangedType.ItemRemoved doesn't give access to the removed element and ElementRemoved does.
+			if (e.ListChangedType == ListChangedType.ItemAdded)
+			{
+				ClassAdded?.Invoke(classes[e.NewIndex]);
+			}
+		}
+
+		private void Classes_ElementRemoved(object sender, CollectionElementRemovedEventArgs<ClassNode> e) => ClassRemoved?.Invoke(e.InvolvedElement);
+		private void Enums_ElementRemoved(object sender, CollectionElementRemovedEventArgs<EnumDescription> e) => EnumRemoved?.Invoke(e.InvolvedElement);
 
 		public void Dispose()
 		{
@@ -56,7 +79,7 @@ public void AddClass(ClassNode node)
 
 			node.NodesChanged += NodesChanged_Handler;
 
-			ClassAdded?.Invoke(node);
+			// No need to invoke the ClassAdded event here, as it's automatically raised when the class is added to the commandified list. 
 		}
 
 		public bool ContainsClass(Guid uuid)
diff --git a/ReClass.NET/Properties/Resources.Designer.cs b/ReClass.NET/Properties/Resources.Designer.cs
index 3d412074..3738ffbc 100644
--- a/ReClass.NET/Properties/Resources.Designer.cs
+++ b/ReClass.NET/Properties/Resources.Designer.cs
@@ -19,7 +19,7 @@ namespace ReClassNET.Properties {
     // class via a tool like ResGen or Visual Studio.
     // To add or remove a member, edit your .ResX file then rerun ResGen
     // with the /str option, or rebuild your VS project.
-    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
     [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
     internal class Resources {
@@ -190,6 +190,16 @@ internal static System.Drawing.Bitmap B16x16_Button_Array {
             }
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
+        internal static System.Drawing.Bitmap B16x16_Button_AutoName {
+            get {
+                object obj = ResourceManager.GetObject("B16x16_Button_AutoName", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
         /// <summary>
         ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
@@ -1371,7 +1381,7 @@ internal static System.Drawing.Bitmap B32x32_Plugin {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to 2020/10/17 09:45:04
+        ///   Looks up a localized string similar to 2023/07/03 12:55:32
         ///.
         /// </summary>
         internal static string BuildDate {
diff --git a/ReClass.NET/Properties/Resources.resx b/ReClass.NET/Properties/Resources.resx
index 48c2c826..3cee6c55 100644
--- a/ReClass.NET/Properties/Resources.resx
+++ b/ReClass.NET/Properties/Resources.resx
@@ -517,4 +517,7 @@
   <data name="B16x16_Button_NUInt" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>..\Resources\Images\B16x16_Button_NUInt.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
+  <data name="B16x16_Button_AutoName" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\Resources\Images\B16x16_Button_AutoName.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
 </root>
\ No newline at end of file
diff --git a/ReClass.NET/ReClass.NET.csproj b/ReClass.NET/ReClass.NET.csproj
index 0c990cc2..3a98a45a 100644
--- a/ReClass.NET/ReClass.NET.csproj
+++ b/ReClass.NET/ReClass.NET.csproj
@@ -122,6 +122,12 @@
       <SpecificVersion>False</SpecificVersion>
       <HintPath>..\Dependencies\Microsoft.ExceptionMessageBox.dll</HintPath>
     </Reference>
+    <Reference Include="SD.Tools.Algorithmia, Version=1.4.0.0, Culture=neutral, PublicKeyToken=8ede9265bbb8e107, processorArchitecture=MSIL">
+      <HintPath>..\packages\SD.Tools.Algorithmia.1.4.0\lib\net452\SD.Tools.Algorithmia.dll</HintPath>
+    </Reference>
+    <Reference Include="SD.Tools.BCLExtensions, Version=1.2.2.0, Culture=neutral, PublicKeyToken=a3f87088dcb994e1, processorArchitecture=MSIL">
+      <HintPath>..\packages\SD.Tools.BCLExtensions.1.2.2\lib\net452\SD.Tools.BCLExtensions.dll</HintPath>
+    </Reference>
     <Reference Include="System" />
     <Reference Include="System.Core" />
     <Reference Include="System.Design" />
@@ -608,6 +614,7 @@
       <LastGenOutput>Resources.Designer.cs</LastGenOutput>
     </EmbeddedResource>
     <Compile Include="Debugger\RemoteDebugger.Handler.cs" />
+    <None Include="packages.config" />
     <None Include="Properties\Settings.settings">
       <Generator>SettingsSingleFileGenerator</Generator>
       <LastGenOutput>Settings.Designer.cs</LastGenOutput>
@@ -1023,6 +1030,9 @@
   <ItemGroup>
     <None Include="Resources\Images\B16x16_Button_NUInt.png" />
   </ItemGroup>
+  <ItemGroup>
+    <None Include="Resources\Images\B16x16_Button_AutoName.png" />
+  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <PropertyGroup>
     <PreBuildEvent Condition=" '$(OS)' == 'Windows_NT' ">powershell -Command "((Get-Date).ToUniversalTime()).ToString(\"yyyy\/MM\/dd HH:mm:ss\") | Out-File '$(ProjectDir)Resources\BuildDate.txt'"</PreBuildEvent>
diff --git a/ReClass.NET/Resources/Images/B16x16_Button_AutoName.png b/ReClass.NET/Resources/Images/B16x16_Button_AutoName.png
new file mode 100644
index 00000000..bfdd7e64
Binary files /dev/null and b/ReClass.NET/Resources/Images/B16x16_Button_AutoName.png differ
diff --git a/ReClass.NET/Settings.cs b/ReClass.NET/Settings.cs
index b5d9268b..32eafc3d 100644
--- a/ReClass.NET/Settings.cs
+++ b/ReClass.NET/Settings.cs
@@ -1,11 +1,36 @@
-using System.Drawing;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
 using System.Text;
+using System.Windows.Forms;
+using ReClassNET.Nodes;
 using ReClassNET.Util;
 
 namespace ReClassNET
 {
 	public class Settings
 	{
+		private readonly Dictionary<Type, Keys> _shortcutKeyPerNode;
+
+		public Settings()
+		{
+			_shortcutKeyPerNode = new Dictionary<Type, Keys>
+								  {
+									  { typeof(Hex64Node), Keys.Control | Keys.Shift | Keys.D6 },
+									  { typeof(ClassInstanceNode), Keys.Control | Keys.Shift | Keys.C },
+									  { typeof(FloatNode), Keys.Control | Keys.Shift | Keys.F },
+									  { typeof(Hex8Node), Keys.Control | Keys.Shift | Keys.B },
+									  { typeof(PointerNode), Keys.Control | Keys.Shift | Keys.P },
+									  { typeof(Vector2Node), Keys.Control | Keys.Shift | Keys.D2 },
+									  { typeof(Vector3Node), Keys.Control | Keys.Shift | Keys.D3 },
+									  { typeof(Vector4Node), Keys.Control | Keys.Shift | Keys.D4 },
+									  { typeof(VirtualMethodTableNode), Keys.Control | Keys.Shift | Keys.V },
+									  { typeof(BoolNode), Keys.Control | Keys.Shift | Keys.O },
+									  { typeof(EnumNode), Keys.Control | Keys.Shift | Keys.E },
+									  { typeof(Int32Node), Keys.Control | Keys.Shift | Keys.I }
+								  };
+		}
+		
 		// Application Settings
 
 		public string LastProcess { get; set; } = string.Empty;
@@ -75,6 +100,11 @@ public class Settings
 		public Color PluginColor { get; set; } = Color.FromArgb(255, 0, 255);
 
 		public CustomDataMap CustomData { get; } = new CustomDataMap();
+		
+		public Keys GetShortcutKeyForNodeType(Type nodeType)
+		{
+			return !_shortcutKeyPerNode.TryGetValue(nodeType, out var shortcutKeys) ? Keys.None : shortcutKeys;
+		}
 
 		public Settings Clone() => MemberwiseClone() as Settings;
 	}
diff --git a/ReClass.NET/UI/HotSpot.cs b/ReClass.NET/UI/HotSpot.cs
index 3a0d4bc0..27b949d0 100644
--- a/ReClass.NET/UI/HotSpot.cs
+++ b/ReClass.NET/UI/HotSpot.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
 using System.Drawing;
 using ReClassNET.Memory;
 using ReClassNET.Nodes;
diff --git a/ReClass.NET/UI/NodeTypesBuilder.cs b/ReClass.NET/UI/NodeTypesBuilder.cs
index 8d519022..79d4bfbe 100644
--- a/ReClass.NET/UI/NodeTypesBuilder.cs
+++ b/ReClass.NET/UI/NodeTypesBuilder.cs
@@ -14,6 +14,7 @@ internal static class NodeTypesBuilder
 	{
 		private static readonly List<Type[]> defaultNodeTypeGroupList = new List<Type[]>();
 		private static readonly Dictionary<Plugin, IReadOnlyList<Type>> pluginNodeTypes = new Dictionary<Plugin, IReadOnlyList<Type>>();
+		private static readonly HashSet<Type> nodeTypesWhichCanOverflowInToolbar;
 
 		static NodeTypesBuilder()
 		{
@@ -27,6 +28,9 @@ static NodeTypesBuilder()
 			defaultNodeTypeGroupList.Add(new[] { typeof(PointerNode), typeof(ArrayNode), typeof(UnionNode) });
 			defaultNodeTypeGroupList.Add(new[] { typeof(ClassInstanceNode) });
 			defaultNodeTypeGroupList.Add(new[] { typeof(VirtualMethodTableNode), typeof(FunctionNode), typeof(FunctionPtrNode) });
+
+			// define the node types which can overflow in the toolbar if the window is too narrow. Add types here which aren't used that much 
+			nodeTypesWhichCanOverflowInToolbar = new HashSet<Type> { typeof(NIntNode), typeof(NUIntNode), typeof(BitFieldNode), typeof(Utf16TextNode), typeof(Utf16TextPtrNode) } ;
 		}
 
 		public static void AddPluginNodeGroup(Plugin plugin, IReadOnlyList<Type> nodeTypes)
@@ -57,14 +61,16 @@ public static IEnumerable<ToolStripItem> CreateToolStripButtons(Action<Type> han
 
 			return CreateToolStripItems(t =>
 			{
-				GetNodeInfoFromType(t, out var label, out var icon);
+				GetNodeInfoFromType(t, out var label, out var icon, out var shortcutKeys);
 
-				var item = new TypeToolStripButton
+				var item = new TypeToolStripMenuItem
 				{
 					Value = t,
 					ToolTipText = label,
 					DisplayStyle = ToolStripItemDisplayStyle.Image,
-					Image = icon
+					Image = icon,
+					ShortcutKeys = shortcutKeys,
+					Overflow = nodeTypesWhichCanOverflowInToolbar.Contains(t) ? ToolStripItemOverflow.AsNeeded : ToolStripItemOverflow.Never,
 				};
 				item.Click += clickHandler;
 				return item;
@@ -74,7 +80,7 @@ public static IEnumerable<ToolStripItem> CreateToolStripButtons(Action<Type> han
 				Image = p.Icon
 			}, t =>
 			{
-				GetNodeInfoFromType(t, out var label, out var icon);
+				GetNodeInfoFromType(t, out var label, out var icon, out var shortcutKeys);
 
 				var item = new TypeToolStripMenuItem
 				{
@@ -95,13 +101,14 @@ public static IEnumerable<ToolStripItem> CreateToolStripMenuItems(Action<Type> h
 
 			var items = CreateToolStripItems(t =>
 			{
-				GetNodeInfoFromType(t, out var label, out var icon);
+				GetNodeInfoFromType(t, out var label, out var icon, out var shortcutKeys);
 
 				var item = new TypeToolStripMenuItem
 				{
 					Value = t,
 					Text = label,
-					Image = icon
+					Image = icon,
+					ShortcutKeys = shortcutKeys,
 				};
 				item.Click += clickHandler;
 				return item;
@@ -166,10 +173,12 @@ private static IEnumerable<ToolStripItem> CreateToolStripItems(Func<Type, ToolSt
 			return items;
 		}
 
-		private static void GetNodeInfoFromType(Type nodeType, out string label, out Image icon)
+		private static void GetNodeInfoFromType(Type nodeType, out string label, out Image icon, out Keys shortcutKeys)
 		{
 			Contract.Requires(nodeType != null);
 
+			shortcutKeys = Program.Settings.GetShortcutKeyForNodeType(nodeType);
+
 			var node = BaseNode.CreateInstanceFromType(nodeType, false);
 			if (node == null)
 			{
diff --git a/ReClass.NET/packages.config b/ReClass.NET/packages.config
new file mode 100644
index 00000000..67c03fdf
--- /dev/null
+++ b/ReClass.NET/packages.config
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="SD.Tools.Algorithmia" version="1.4.0" targetFramework="net472" />
+  <package id="SD.Tools.BCLExtensions" version="1.2.2" targetFramework="net472" />
+</packages>
\ No newline at end of file