diff --git a/source/ChromeDevTools/MasterDevs.ChromeDevTools.csproj b/source/ChromeDevTools/MasterDevs.ChromeDevTools.csproj
index 5c08970b191b5e4cd62f325fcaa6eb4934e51827..c8c40e0002b9fbb8417172315a19559d640a0dcc 100644
--- a/source/ChromeDevTools/MasterDevs.ChromeDevTools.csproj
+++ b/source/ChromeDevTools/MasterDevs.ChromeDevTools.csproj
@@ -880,6 +880,7 @@
     <Compile Include="Protocol\Worker\WorkerCreatedEvent.cs" />
     <Compile Include="Protocol\Worker\WorkerTerminatedEvent.cs" />
     <Compile Include="Serialization\MessageContractResolver.cs" />
+    <Compile Include="SupportedByAttribute.cs" />
   </ItemGroup>
   <ItemGroup>
     <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
diff --git a/source/ChromeDevTools/SupportedByAttribute.cs b/source/ChromeDevTools/SupportedByAttribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..73fb8cf2744063a1d1a39c0a33821cbfd0826d7a
--- /dev/null
+++ b/source/ChromeDevTools/SupportedByAttribute.cs
@@ -0,0 +1,24 @@
+using System;
+
+namespace MasterDevs.ChromeDevTools
+{
+    [AttributeUsage(AttributeTargets.Class)]
+    public class SupportedByAttribute : Attribute
+    {
+        public SupportedByAttribute(string browser)
+        {
+            if (browser == null)
+            {
+                throw new ArgumentNullException(nameof(browser));
+            }
+
+            this.Browser = browser;
+        }
+
+        public string Browser
+        {
+            get;
+            set;
+        }
+    }
+}
diff --git a/source/MasterDevs.ChromeDevTools.sln b/source/MasterDevs.ChromeDevTools.sln
index 521d04e064ce6c4905d1f4df693e98e8a9179778..a20ee809d611088a42c468cbc9271e130d10190d 100644
--- a/source/MasterDevs.ChromeDevTools.sln
+++ b/source/MasterDevs.ChromeDevTools.sln
@@ -1,7 +1,7 @@
 
 Microsoft Visual Studio Solution File, Format Version 12.00
 # Visual Studio 14
-VisualStudioVersion = 14.0.24720.0
+VisualStudioVersion = 14.0.25123.0
 MinimumVisualStudioVersion = 10.0.40219.1
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{0D43D20B-6D51-4CBC-BD30-F17B8CA65678}"
 	ProjectSection(SolutionItems) = preProject
@@ -22,6 +22,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MasterDevs.ChromeDevTools.P
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MasterDevs.ChromeDevTools.Sample", "Sample\MasterDevs.ChromeDevTools.Sample.csproj", "{36138327-0A72-44E3-B9DB-C4E6155AAFD5}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MasterDevs.ChromeDevTools.ProtocolGenerator.Tests", "ProtocolGenerator.Tests\MasterDevs.ChromeDevTools.ProtocolGenerator.Tests.csproj", "{4C3A1910-79C5-43C0-8599-89921482B38B}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -40,6 +42,10 @@ Global
 		{36138327-0A72-44E3-B9DB-C4E6155AAFD5}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{36138327-0A72-44E3-B9DB-C4E6155AAFD5}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{36138327-0A72-44E3-B9DB-C4E6155AAFD5}.Release|Any CPU.Build.0 = Release|Any CPU
+		{4C3A1910-79C5-43C0-8599-89921482B38B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{4C3A1910-79C5-43C0-8599-89921482B38B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{4C3A1910-79C5-43C0-8599-89921482B38B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{4C3A1910-79C5-43C0-8599-89921482B38B}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
diff --git a/source/ProtocolGenerator.Tests/CommandTests.cs b/source/ProtocolGenerator.Tests/CommandTests.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e4835cf75db2f9c041a724f7cb26822ee5c8a95f
--- /dev/null
+++ b/source/ProtocolGenerator.Tests/CommandTests.cs
@@ -0,0 +1,35 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MasterDevs.ChromeDevTools.ProtocolGenerator.Tests
+{
+    [TestClass]
+    public class CommandTests
+    {
+        [TestMethod]
+        [DeploymentItem(DeploymentItems.Inspector11)]
+        [DeploymentItem(DeploymentItems.Protocol)]
+        public void EqualsTest()
+        {
+            var inspector11 = ProtocolProcessor.LoadProtocol(DeploymentItems.Inspector11, "inspector-1.1");
+            var protocol = ProtocolProcessor.LoadProtocol(DeploymentItems.Protocol, "protocol");
+
+            ProtocolProcessor.ResolveTypeReferences(inspector11, new Dictionary<string, string>());
+            ProtocolProcessor.ResolveTypeReferences(protocol, new Dictionary<string, string>());
+
+            var stopScreencast10 = inspector11.GetDomain("Page").GetCommand("stopScreencast");
+            var stopScreencastTip = protocol.GetDomain("Page").GetCommand("stopScreencast");
+
+            // Quick fact check: both methods have the same string equivalent,
+            // void stopScreencast()
+            Assert.AreEqual<string>(stopScreencast10.ToString(), stopScreencastTip.ToString());
+
+            Assert.IsTrue(stopScreencast10.Equals(stopScreencastTip));
+            Assert.IsTrue(stopScreencastTip.Equals(stopScreencast10));
+        }
+    }
+}
diff --git a/source/ProtocolGenerator.Tests/DeploymentItems.cs b/source/ProtocolGenerator.Tests/DeploymentItems.cs
new file mode 100644
index 0000000000000000000000000000000000000000..dec0e235aab89c6757e46a6f6e525dfaf32766c2
--- /dev/null
+++ b/source/ProtocolGenerator.Tests/DeploymentItems.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MasterDevs.ChromeDevTools.ProtocolGenerator.Tests
+{
+    class DeploymentItems
+    {
+        public const string Inspector10 = "Inspector-1.0.json";
+        public const string Inspector11 = "Inspector-1.1.json";
+        public const string Protocol = "protocol.json";
+        public const string InspectoriOS8 = "Inspector-ios-8.0.json";
+    }
+}
diff --git a/source/ProtocolGenerator.Tests/MasterDevs.ChromeDevTools.ProtocolGenerator.Tests.csproj b/source/ProtocolGenerator.Tests/MasterDevs.ChromeDevTools.ProtocolGenerator.Tests.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..8e37f6572a6f57b277fbd82e2e651b5ae863513c
--- /dev/null
+++ b/source/ProtocolGenerator.Tests/MasterDevs.ChromeDevTools.ProtocolGenerator.Tests.csproj
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{4C3A1910-79C5-43C0-8599-89921482B38B}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>MasterDevs.ChromeDevTools.ProtocolGenerator.Tests</RootNamespace>
+    <AssemblyName>MasterDevs.ChromeDevTools.ProtocolGenerator.Tests</AssemblyName>
+    <TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+    <ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
+    <IsCodedUITest>False</IsCodedUITest>
+    <TestProjectType>UnitTest</TestProjectType>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+  </ItemGroup>
+  <Choose>
+    <When Condition="('$(VisualStudioVersion)' == '10.0' or '$(VisualStudioVersion)' == '') and '$(TargetFrameworkVersion)' == 'v3.5'">
+      <ItemGroup>
+        <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
+      </ItemGroup>
+    </When>
+    <Otherwise>
+      <ItemGroup>
+        <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework" />
+      </ItemGroup>
+    </Otherwise>
+  </Choose>
+  <ItemGroup>
+    <Compile Include="CommandTests.cs" />
+    <Compile Include="DeploymentItems.cs" />
+    <Compile Include="ProtocolProcessorTests.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="TypeTests.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\ProtocolGenerator\MasterDevs.ChromeDevTools.ProtocolGenerator.csproj">
+      <Project>{97c7fcf5-1964-4878-b7cd-63448ca403b1}</Project>
+      <Name>MasterDevs.ChromeDevTools.ProtocolGenerator</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="..\ProtocolGenerator\Inspector-1.0.json">
+      <Link>Inspector-1.0.json</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="..\ProtocolGenerator\Inspector-iOS-8.0.json">
+      <Link>Inspector-iOS-8.0.json</Link>
+    </None>
+    <None Include="..\ProtocolGenerator\protocol.json">
+      <Link>protocol.json</Link>
+    </None>
+  </ItemGroup>
+  <Choose>
+    <When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
+      <ItemGroup>
+        <Reference Include="Microsoft.VisualStudio.QualityTools.CodedUITestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+          <Private>False</Private>
+        </Reference>
+        <Reference Include="Microsoft.VisualStudio.TestTools.UITest.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+          <Private>False</Private>
+        </Reference>
+        <Reference Include="Microsoft.VisualStudio.TestTools.UITest.Extension, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+          <Private>False</Private>
+        </Reference>
+        <Reference Include="Microsoft.VisualStudio.TestTools.UITesting, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+          <Private>False</Private>
+        </Reference>
+      </ItemGroup>
+    </When>
+  </Choose>
+  <Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
diff --git a/source/ProtocolGenerator.Tests/Properties/AssemblyInfo.cs b/source/ProtocolGenerator.Tests/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..27cd8c0576a8621539ffbd4dc216261072a9a4e3
--- /dev/null
+++ b/source/ProtocolGenerator.Tests/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("MasterDevs.ChromeDevTools.ProtocolGenerator.Tests")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("MasterDevs.ChromeDevTools.ProtocolGenerator.Tests")]
+[assembly: AssemblyCopyright("Copyright ©  2016")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("4c3a1910-79c5-43c0-8599-89921482b38b")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/source/ProtocolGenerator.Tests/ProtocolProcessorTests.cs b/source/ProtocolGenerator.Tests/ProtocolProcessorTests.cs
new file mode 100644
index 0000000000000000000000000000000000000000..371d1adbd30d98380de0a837e17c090d22a54c72
--- /dev/null
+++ b/source/ProtocolGenerator.Tests/ProtocolProcessorTests.cs
@@ -0,0 +1,73 @@
+using System;
+using System.Linq;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System.Collections.Generic;
+
+namespace MasterDevs.ChromeDevTools.ProtocolGenerator.Tests
+{
+    [TestClass]
+    public class ProtocolProcessorTests
+    {
+        /// <summary>
+        /// Loads the Chrome-1.0 protocol and makes sure the type <c>Network.FrameId</c> type reference in the
+        /// <c>Runtime.Evaluate</c> command is resolved correctly to the <c>string</c> primitive.
+        /// </summary>
+        [TestMethod]
+        [DeploymentItem(DeploymentItems.Inspector10)]
+        public void ResolveTypeReferencesCommandParameterTest()
+        {
+            Protocol p = ProtocolProcessor.LoadProtocol(DeploymentItems.Inspector10, "Chrome-1.0");
+            ProtocolProcessor.ResolveTypeReferences(p, new Dictionary<string, string>());
+
+            var evaluateCommand = p.GetDomain("Runtime").GetCommand("evaluate");
+            var frameIdParameter = evaluateCommand.GetParameter("frameId");
+
+            Assert.AreEqual("string", frameIdParameter.TypeName);
+        }
+
+        [TestMethod]
+        [DeploymentItem(DeploymentItems.Inspector10)]
+        public void ResolveTypeReferencesCommandParameterTest2()
+        {
+            Protocol p = ProtocolProcessor.LoadProtocol(DeploymentItems.Inspector10, "Chrome-1.0");
+            ProtocolProcessor.ResolveTypeReferences(p, new Dictionary<string, string>());
+
+            var addInspectedNodeCommand = p.GetDomain("Console").GetCommand("addInspectedNode");
+            var nodeId = addInspectedNodeCommand.GetParameter("nodeId");
+
+            Assert.AreEqual("integer", nodeId.TypeName);
+        }
+
+        [TestMethod]
+        [DeploymentItem(DeploymentItems.InspectoriOS8)]
+        public void ResolveTypeReferencesCommandReturnValueTest()
+        {
+            Dictionary<string, string> explicitMappings = new Dictionary<string, string>();
+            explicitMappings.Add("Page.Cookie", "Network.Cookie");
+
+            Protocol p = ProtocolProcessor.LoadProtocol(DeploymentItems.InspectoriOS8, "iOS-8.0");
+            ProtocolProcessor.ResolveTypeReferences(p, explicitMappings);
+
+            var getCookiesCommand = p.GetDomain("Page").GetCommand("getCookies");
+            var cookieArray = getCookiesCommand.Returns.Single();
+
+            Assert.AreEqual("Network.Cookie[]", cookieArray.TypeName);
+        }
+
+        [TestMethod]
+        [DeploymentItem(DeploymentItems.InspectoriOS8)]
+        public void ResolveTypeReferencesCommandReturnValueTest2()
+        {
+            Dictionary<string, string> explicitMappings = new Dictionary<string, string>();
+            explicitMappings.Add("GenericTypes.SearchMatch", "Debugger.SearchMatch");
+
+            Protocol p = ProtocolProcessor.LoadProtocol(DeploymentItems.InspectoriOS8, "iOS-8.0");
+            ProtocolProcessor.ResolveTypeReferences(p, explicitMappings);
+
+            var searchInResourceCommand = p.GetDomain("Page").GetCommand("searchInResource");
+            var searchMatchArray = searchInResourceCommand.Returns.Single();
+
+            Assert.AreEqual("Debugger.SearchMatch[]", searchMatchArray.TypeName);
+        }
+    }
+}
diff --git a/source/ProtocolGenerator.Tests/TypeTests.cs b/source/ProtocolGenerator.Tests/TypeTests.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1b0f6d76e2580c2da2cc4f18d6049dfd255ab42b
--- /dev/null
+++ b/source/ProtocolGenerator.Tests/TypeTests.cs
@@ -0,0 +1,39 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MasterDevs.ChromeDevTools.ProtocolGenerator.Tests
+{
+    [TestClass]
+    public class TypeTests
+    {
+
+        [TestMethod]
+        [DeploymentItem(DeploymentItems.Inspector10)]
+        public void TypeNameTest()
+        {
+            Protocol p = ProtocolProcessor.LoadProtocol(DeploymentItems.Inspector10, "Chrome-1.0");
+
+            var evaluateCommand = p.GetDomain("Page").GetCommand("searchInResource");
+            var result = evaluateCommand.Returns.Single();
+
+            Assert.AreEqual("SearchMatch[]", result.TypeName.ToString());
+        }
+
+        [TestMethod]
+        [DeploymentItem(DeploymentItems.Inspector10)]
+        public void ToStringTest()
+        {
+            Protocol p = ProtocolProcessor.LoadProtocol(DeploymentItems.Inspector10, "Chrome-1.0");
+
+            var evaluateCommand = p.GetDomain("Page").GetCommand("searchInResource");
+            var result = evaluateCommand.Returns.Single();
+            var items = result.Items;
+
+            Assert.AreEqual("SearchMatch", items.ToString());
+        }
+    }
+}
diff --git a/source/ProtocolGenerator/CollectionExtensions.cs b/source/ProtocolGenerator/CollectionExtensions.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d901618c06777480ee25a90aa6769dd0a0a2615d
--- /dev/null
+++ b/source/ProtocolGenerator/CollectionExtensions.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MasterDevs.ChromeDevTools.ProtocolGenerator
+{
+    static class CollectionExtensions
+    {
+        public static bool CollectionEqual<T>(this ICollection<T> x, ICollection<T> y)
+        {
+            if (x == null || y == null)
+            {
+                return false;
+            }
+
+            if(x.Count != y.Count)
+            {
+                return false;
+            }
+
+            return x.All(e => y.Contains(e));
+        }
+
+        public static int GetCollectionHashCode<T>(this ICollection<T> x)
+        {
+            int hash = 17;
+
+            unchecked
+            {
+                foreach (var e in x)
+                {
+                    hash = hash * 23 + e.GetHashCode();
+                }
+            }
+
+            return hash;
+        }
+    }
+}
diff --git a/source/ProtocolGenerator/Command.cs b/source/ProtocolGenerator/Command.cs
index df3886ee795152cf0bfcc4c1d117f46b4f22b3ae..1bc90d0866630fb1d6b44d2f66d6c5f92ee2d932 100644
--- a/source/ProtocolGenerator/Command.cs
+++ b/source/ProtocolGenerator/Command.cs
@@ -1,8 +1,12 @@
-using System.Collections.ObjectModel;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Text;
+using System.Linq;
+using System;
 
 namespace MasterDevs.ChromeDevTools.ProtocolGenerator
 {
-    class Command : ProtocolItem
+    public class Command : ProtocolItem
     {
         public Command()
         {
@@ -23,6 +27,9 @@ namespace MasterDevs.ChromeDevTools.ProtocolGenerator
             set;
         }
 
+        /// <remarks>
+        /// This property is currently ignored.
+        /// </remarks>
         public Collection<string> Handlers
         {
             get;
@@ -46,5 +53,101 @@ namespace MasterDevs.ChromeDevTools.ProtocolGenerator
             get;
             set;
         }
+
+        public override bool Equals(object obj)
+        {
+            var other = obj as Command;
+
+            if (other == null)
+            {
+                return false;
+            }
+
+            bool equals = base.Equals(obj);
+            equals &= this.Returns.SequenceEqual(other.Returns);
+            equals &= Property.Equals(this.Error, other.Error);
+            equals &= this.Parameters.SequenceEqual(other.Parameters);
+            return equals;
+        }
+
+        public override int GetHashCode()
+        {
+            unchecked
+            {
+                int hash = base.GetHashCode();
+                hash = hash * 23 + this.Redirect.GetHashCode();
+
+                if (this.Error != null)
+                {
+                    hash = hash * 23 + this.Error.GetHashCode();
+                }
+                
+                hash = hash * 23 + this.Parameters.GetCollectionHashCode();
+                return hash;
+            }
+        }
+
+        public override string ToString()
+        {
+            StringBuilder name = new StringBuilder();
+
+            if (this.Returns.Count > 0)
+            {
+                name.Append("(");
+                bool isFirst = true;
+
+                foreach (var p in this.Returns)
+                {
+                    if (isFirst)
+                    {
+                        isFirst = false;
+                    }
+                    else
+                    {
+                        name.Append(", ");
+                    }
+
+                    name.Append(p.TypeName);
+                    name.Append(" ");
+                    name.Append(p.Name);
+                }
+
+                name.Append(") ");
+            }
+            else
+            {
+                name.Append("void ");
+            }
+
+            name.Append(this.Name);
+
+            name.Append("(");
+
+            bool isFirstParam = true;
+            foreach (var p in this.Parameters)
+            {
+                if (isFirstParam)
+                {
+                    isFirstParam = false;
+                }
+                else
+                {
+                    name.Append(", ");
+                }
+
+                name.Append(p.TypeName);
+                name.Append(" ");
+                name.Append(p.Name);
+            }
+
+            name.Append(")");
+
+            return name.ToString();
+        }
+
+        public Property GetParameter(string name)
+        {
+            return this.Parameters.SingleOrDefault(p => string.Equals(p.Name, name, StringComparison.OrdinalIgnoreCase));
+        }
     }
 }
diff --git a/source/ProtocolGenerator/Domain.cs b/source/ProtocolGenerator/Domain.cs
index 248f6b132fc68c3a61512b48c844609d40365e3c..a707947291ead3d5f658dbf253806220c0e99ab8 100644
--- a/source/ProtocolGenerator/Domain.cs
+++ b/source/ProtocolGenerator/Domain.cs
@@ -1,9 +1,11 @@
 using Newtonsoft.Json;
+using System;
 using System.Collections.ObjectModel;
+using System.Linq;
 
 namespace MasterDevs.ChromeDevTools.ProtocolGenerator
 {
-    class Domain : ProtocolItem
+    public class Domain : ProtocolItem
     {
         public Domain()
         {
@@ -48,5 +50,15 @@ namespace MasterDevs.ChromeDevTools.ProtocolGenerator
             get;
             set;
         }
+
+        public Command GetCommand(string name)
+        {
+            return this.Commands.SingleOrDefault(c => string.Equals(c.Name, name, StringComparison.OrdinalIgnoreCase));
+        }
+
+        public Type GetType(string name)
+        {
+            return this.Types.SingleOrDefault(t => string.Equals(t.Name, name, StringComparison.OrdinalIgnoreCase));
+        }
     }
 }
diff --git a/source/ProtocolGenerator/Event.cs b/source/ProtocolGenerator/Event.cs
index 557661197ed846d882bea88dadd16e980c859750..2456dc94e67fcaace2dd87c8fabf9cedf7230380 100644
--- a/source/ProtocolGenerator/Event.cs
+++ b/source/ProtocolGenerator/Event.cs
@@ -2,7 +2,7 @@
 
 namespace MasterDevs.ChromeDevTools.ProtocolGenerator
 {
-    class Event : ProtocolItem
+    public class Event : ProtocolItem
     {
         public Event()
         {
diff --git a/source/ProtocolGenerator/MasterDevs.ChromeDevTools.ProtocolGenerator.csproj b/source/ProtocolGenerator/MasterDevs.ChromeDevTools.ProtocolGenerator.csproj
index 4a58f80391dbf58d9e10dd4e977a50dc697846f2..fc1147ccef27175b3f20564cdb898c1e3800d7b0 100644
--- a/source/ProtocolGenerator/MasterDevs.ChromeDevTools.ProtocolGenerator.csproj
+++ b/source/ProtocolGenerator/MasterDevs.ChromeDevTools.ProtocolGenerator.csproj
@@ -50,14 +50,18 @@
     <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="CollectionExtensions.cs" />
     <Compile Include="Command.cs" />
     <Compile Include="Domain.cs" />
     <Compile Include="Event.cs" />
+    <Compile Include="NameEqualityComparer.cs" />
     <Compile Include="Program.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Property.cs" />
     <Compile Include="Protocol.cs" />
     <Compile Include="ProtocolItem.cs" />
+    <Compile Include="ProtocolMerger.cs" />
+    <Compile Include="ProtocolProcessor.cs" />
     <Compile Include="Type.cs" />
     <Compile Include="Version.cs" />
   </ItemGroup>
diff --git a/source/ProtocolGenerator/NameEqualityComparer.cs b/source/ProtocolGenerator/NameEqualityComparer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e79082f11b98ea3af39ef7f0f200fea1e197c693
--- /dev/null
+++ b/source/ProtocolGenerator/NameEqualityComparer.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MasterDevs.ChromeDevTools.ProtocolGenerator
+{
+    class NameEqualityComparer<T> : EqualityComparer<T>
+        where T : ProtocolItem
+    {
+        public static NameEqualityComparer<T> Instance
+        { get; } = new NameEqualityComparer<T>();
+
+        public override bool Equals(T x, T y)
+        {
+            if (x == null || y == null)
+            {
+                return false;
+            }
+
+            return string.Equals(x.Name, y.Name, StringComparison.OrdinalIgnoreCase);
+        }
+
+        public override int GetHashCode(T obj)
+        {
+            if (obj == null)
+            {
+                throw new ArgumentNullException(nameof(obj));
+            }
+
+            return StringComparer.OrdinalIgnoreCase.GetHashCode(obj.Name);
+        }
+    }
+}
diff --git a/source/ProtocolGenerator/Program.cs b/source/ProtocolGenerator/Program.cs
index 0b16d5fe7e0267808d66d16d60ea191d355ff2fb..3a577f4c716d3d391cb3eccfb9c037a40cc4dfdf 100644
--- a/source/ProtocolGenerator/Program.cs
+++ b/source/ProtocolGenerator/Program.cs
@@ -2,6 +2,7 @@
 using Newtonsoft.Json.Linq;
 using System;
 using System.Collections.Generic;
+using System.Collections.ObjectModel;
 using System.IO;
 using System.Linq;
 using System.Text;
@@ -23,20 +24,43 @@ namespace MasterDevs.ChromeDevTools.ProtocolGenerator
         private static Dictionary<string, List<string>> _DomainEvents = new Dictionary<string, List<string>>();
         private static Dictionary<string, string> _SimpleTypes = new Dictionary<string, string>();
 
-        private static Protocol LoadProtocol(string path)
-        {
-            string json = File.ReadAllText(path);
-            JsonSerializerSettings settings = new JsonSerializerSettings();
-            settings.MissingMemberHandling = MissingMemberHandling.Error;
-            settings.MetadataPropertyHandling = MetadataPropertyHandling.Ignore;
-            Protocol p = JsonConvert.DeserializeObject<Protocol>(json, settings);
-            return p;
-        }
-
         private static void Main(string[] args)
         {
-            var filePath = "protocol.json";
-            var protocolObject = LoadProtocol(filePath);
+            // At this point in time, we only process the most recent Chrome
+            // and iOS (Safari) protocols.
+            Dictionary<string, string> protocolFiles = new Dictionary<string, string>();
+            //protocolFiles.Add("Chrome-0.1", "Inspector-0.1.json");
+            //protocolFiles.Add("Chrome-1.0", "Inspector-1.0.json");
+            //protocolFiles.Add("Chrome-1.1", "Inspector-1.1.json");
+            protocolFiles.Add("Chrome-Tip", "protocol.json");
+            //protocolFiles.Add("iOS-7.0", "Inspector-iOS-7.0.json");
+            //protocolFiles.Add("iOS-8.0", "Inspector-iOS-8.0.json");
+            //protocolFiles.Add("iOS-9.0", "Inspector-iOS-9.0.json");
+            protocolFiles.Add("iOS-9.3", "Inspector-iOS-9.3.json");
+
+            Collection<Protocol> protocols = new Collection<Protocol>();
+
+            // "Explicit mappings" allow us to map one type reference to another. This is a
+            // rather hard-coded way of doing things, and is only used when the same type
+            // has different names accross different versions of the dev tools - e.g. the RGBA
+            // type which is named RGBAColor for Safari.
+            Dictionary<string, string> explicitMappings = new Dictionary<string, string>();
+            explicitMappings.Add("DOM.RGBAColor", "RGBA");
+            explicitMappings.Add("Page.Cookie", "Network.Cookie");
+            explicitMappings.Add("GenericTypes.SearchMatch", "Debugger.SearchMatch");
+
+            foreach (var protocolFile in protocolFiles)
+            {
+                Protocol p = ProtocolProcessor.LoadProtocol(protocolFile.Value, protocolFile.Key);
+                ProtocolProcessor.ResolveTypeReferences(p, explicitMappings);
+                protocols.Add(p);
+            }
+
+            Protocol protocolObject = new Protocol();
+            foreach(var protocol in protocols)
+            {
+                ProtocolMerger.Merge(protocol, protocolObject);
+            }
 
             var outputFolder = "OutputProtocol";
             if (args.Length > 0)
@@ -79,9 +103,9 @@ namespace MasterDevs.ChromeDevTools.ProtocolGenerator
             {
                 var propertyType = type.Kind;
                 var typeName = type.Name;
-                if (type.Enum.Any()
-                    || type.Properties.Any()
-                    || "object" == propertyType)
+                if (type.IsEnum()
+                    || type.IsClass()
+                    || type.IsObject())
                 {
                     propertyType = domain + "." + typeName;
                 }
@@ -183,10 +207,10 @@ namespace MasterDevs.ChromeDevTools.ProtocolGenerator
             var parameters = evnt.Parameters;
             // ignoreing "handlers" ... i'm not sure what they are for yet
             _DomainEvents[domainDirectoryInfo.Name].Add(eventName);
-            WriteEvent(domainDirectoryInfo, eventName, description, parameters);
+            WriteEvent(domainDirectoryInfo, eventName, description, parameters, evnt.SupportedBy);
         }
 
-        private static void WriteEvent(DirectoryInfo domainDirectoryInfo, string eventName, string description, IEnumerable<Property> parameters)
+        private static void WriteEvent(DirectoryInfo domainDirectoryInfo, string eventName, string description, IEnumerable<Property> parameters, IEnumerable<string> supportedBy)
         {
             var className = ToCamelCase(eventName) + EventSubclass;
             var sb = new StringBuilder();
@@ -205,6 +229,7 @@ namespace MasterDevs.ChromeDevTools.ProtocolGenerator
             }
             sb.AppendFormat("\t[{0}({1}.{2}.{3})]", EventAttribute, ProtocolNameClass, domainDirectoryInfo.Name, ToCamelCase(eventName));
             sb.AppendLine();
+            WriteSupportedBy(sb, supportedBy);
             sb.AppendFormat("\tpublic class {0}", className);
             sb.AppendLine();
             sb.AppendLine("\t{");
@@ -225,11 +250,11 @@ namespace MasterDevs.ChromeDevTools.ProtocolGenerator
             var parameters = command.Parameters;
             var returnObject = command.Returns;
             _DomainCommands[domainDirectoryInfo.Name].Add(commandName);
-            WriteCommand(domainDirectoryInfo, commandName, description, parameters);
-            WriteCommandResponse(domainDirectoryInfo, commandName, description, returnObject);
+            WriteCommand(domainDirectoryInfo, commandName, description, parameters, command.SupportedBy);
+            WriteCommandResponse(domainDirectoryInfo, commandName, description, returnObject, command.SupportedBy);
         }
 
-        private static void WriteCommandResponse(DirectoryInfo domainDirectoryInfo, string commandName, string description, IEnumerable<Property> returnObject)
+        private static void WriteCommandResponse(DirectoryInfo domainDirectoryInfo, string commandName, string description, IEnumerable<Property> returnObject, IEnumerable<string> supportedBy)
         {
             var className = ToCamelCase(commandName) + CommandResponseSubclass;
             var sb = new StringBuilder();
@@ -249,6 +274,7 @@ namespace MasterDevs.ChromeDevTools.ProtocolGenerator
             }
             sb.AppendFormat("\t[{0}({1}.{2}.{3})]", CommandResponseAttribute, ProtocolNameClass, domainDirectoryInfo.Name, ToCamelCase(commandName));
             sb.AppendLine();
+            WriteSupportedBy(sb, supportedBy);
             sb.AppendFormat("\tpublic class {0}", className);
             sb.AppendLine();
             sb.AppendLine("\t{");
@@ -261,7 +287,7 @@ namespace MasterDevs.ChromeDevTools.ProtocolGenerator
             WriteToFile(domainDirectoryInfo, className, sb.ToString());
         }
 
-        private static void WriteCommand(DirectoryInfo domainDirectoryInfo, string commandName, string description, IEnumerable<Property> parameters)
+        private static void WriteCommand(DirectoryInfo domainDirectoryInfo, string commandName, string description, IEnumerable<Property> parameters, IEnumerable<string> supportedBy)
         {
             var className = ToCamelCase(commandName) + CommandSubclass;
             var sb = new StringBuilder();
@@ -282,6 +308,7 @@ namespace MasterDevs.ChromeDevTools.ProtocolGenerator
             }
             sb.AppendFormat("\t[{0}({1}.{2}.{3})]", CommandAttribute, ProtocolNameClass, domainDirectoryInfo.Name, ToCamelCase(commandName));
             sb.AppendLine();
+            WriteSupportedBy(sb, supportedBy);
             sb.AppendFormat("\tpublic class {0}", className);
             sb.AppendLine();
             sb.AppendLine("\t{");
@@ -324,6 +351,7 @@ namespace MasterDevs.ChromeDevTools.ProtocolGenerator
             sb.AppendFormat("\t/// {0}", type.Description);
             sb.AppendLine();
             sb.AppendLine("\t/// </summary>");
+            WriteSupportedBy(sb, type);
             sb.AppendFormat("\tpublic class {0}", className);
             sb.AppendLine();
             sb.AppendLine("\t{");
@@ -454,6 +482,7 @@ namespace MasterDevs.ChromeDevTools.ProtocolGenerator
             sb.AppendFormat("\t/// {0}", type.Description);
             sb.AppendLine();
             sb.AppendLine("\t/// </summary>");
+            WriteSupportedBy(sb, type);
             sb.AppendFormat("\tpublic enum {0}", enumName);
             sb.AppendLine();
             sb.AppendLine("\t{");
@@ -467,6 +496,19 @@ namespace MasterDevs.ChromeDevTools.ProtocolGenerator
             WriteToFile(domainDirectoryInfo, enumName, sb.ToString());
         }
 
+        private static void WriteSupportedBy(StringBuilder sb, ProtocolItem type)
+        {
+            WriteSupportedBy(sb, type.SupportedBy);
+        }
+
+        private static void WriteSupportedBy(StringBuilder sb, IEnumerable<string> supportedBy)
+        {
+            foreach(var browser in supportedBy)
+            {
+                sb.AppendLine($"\t[SupportedBy(\"{browser}\")");
+            }
+        }
+
         private static void WriteToFile(DirectoryInfo domainDirectoryInfo, string fileName, string fileContents)
         {
             var fullPath = Path.Combine(domainDirectoryInfo.FullName, fileName + ".cs");
diff --git a/source/ProtocolGenerator/Property.cs b/source/ProtocolGenerator/Property.cs
index 7645385ba81b78ed4611337f92ddccc4bf00f6d0..9002cadf8e2aca6267369b3cb830540bab33b4df 100644
--- a/source/ProtocolGenerator/Property.cs
+++ b/source/ProtocolGenerator/Property.cs
@@ -2,7 +2,7 @@
 
 namespace MasterDevs.ChromeDevTools.ProtocolGenerator
 {
-    class Property : Type
+    public class Property : Type
     {
         [JsonProperty("name")]
         public override string Name
diff --git a/source/ProtocolGenerator/Protocol.cs b/source/ProtocolGenerator/Protocol.cs
index ae206ed86f9019041adf5f86c381dc4faa1895e3..1f5ff07a73dd3593c4dc464a322093524c1f3fac 100644
--- a/source/ProtocolGenerator/Protocol.cs
+++ b/source/ProtocolGenerator/Protocol.cs
@@ -1,9 +1,16 @@
 using System.Collections.ObjectModel;
+using System.Linq;
 
 namespace MasterDevs.ChromeDevTools.ProtocolGenerator
 {
-    class Protocol
+    public class Protocol
     {
+        public Protocol()
+        {
+            this.Compatible = new Collection<string>();
+            this.Domains = new Collection<Domain>();
+        }
+
         public Collection<string> Compatible
         {
             get;
@@ -21,5 +28,34 @@ namespace MasterDevs.ChromeDevTools.ProtocolGenerator
             get;
             set;
         }
+
+        public string SourceFile
+        {
+            get;
+            set;
+        }
+
+        public string Alias
+        {
+            get;
+            set;
+        }
+
+        public Domain GetDomain(string name)
+        {
+            return this.Domains.SingleOrDefault(d => string.Equals(d.Name, name, System.StringComparison.OrdinalIgnoreCase));
+        }
+
+        public override string ToString()
+        {
+            if(this.SourceFile != null)
+            {
+                return $"{this.Alias} ({this.SourceFile})";
+            }
+            else
+            {
+                return this.Alias;
+            }
+        }
     }
 }
diff --git a/source/ProtocolGenerator/ProtocolItem.cs b/source/ProtocolGenerator/ProtocolItem.cs
index 61bae95f698cfcfecdfb486507599265f205e729..3da9daf6ee0e419108eee94f77cc44ad9fc7ca5e 100644
--- a/source/ProtocolGenerator/ProtocolItem.cs
+++ b/source/ProtocolGenerator/ProtocolItem.cs
@@ -1,7 +1,16 @@
-namespace MasterDevs.ChromeDevTools.ProtocolGenerator
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+
+namespace MasterDevs.ChromeDevTools.ProtocolGenerator
 {
-    abstract class ProtocolItem
+    public abstract class ProtocolItem
     {
+        public ProtocolItem()
+        {
+            this.SupportedBy = new Collection<string>();
+        }
+
         public virtual string Description
         {
             get;
@@ -20,9 +29,64 @@
             set;
         }
 
+        public Collection<string> SupportedBy
+        {
+            get;
+        }
+
         public override string ToString()
         {
             return this.Name;
         }
+
+        public static bool Equals(ProtocolItem a, ProtocolItem b)
+        {
+            if (a == null && b == null)
+            {
+                return true;
+            }
+
+            if (a == null || b == null)
+            {
+                return false;
+            }
+
+            if (a.GetType() != b.GetType())
+            {
+                return false;
+            }
+
+            return a.Equals(b);
+        }
+
+        public override bool Equals(object obj)
+        {
+            // In the Equals method, we only include properties which would impact how 
+            // messages are serialized over the wire. E.g.: because the description does not
+            // impact this, but the name does, the description is ignored but the name is included.
+            var other = obj as ProtocolItem;
+
+            if (other == null)
+            {
+                return false;
+            }
+
+            return string.Equals(other.Name, this.Name, StringComparison.OrdinalIgnoreCase);
+        }
+
+        public override int GetHashCode()
+        {
+            unchecked
+            {
+                int hash = 17;
+
+                if (this.Name != null)
+                {
+                    hash = hash * 23 + StringComparer.OrdinalIgnoreCase.GetHashCode(this.Name);
+                }
+
+                return hash;
+            }
+        }
     }
 }
diff --git a/source/ProtocolGenerator/ProtocolMerger.cs b/source/ProtocolGenerator/ProtocolMerger.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b28270c05d19f0a34272a8ea4ebf22e55a4eec19
--- /dev/null
+++ b/source/ProtocolGenerator/ProtocolMerger.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MasterDevs.ChromeDevTools.ProtocolGenerator
+{
+    class ProtocolMerger
+    {
+        public static void Merge(Protocol source, Protocol target)
+        {
+            foreach (var domain in source.Domains)
+            {
+                if (!target.Domains.Contains(domain, NameEqualityComparer<Domain>.Instance))
+                {
+                    target.Domains.Add(domain);
+                }
+                else
+                {
+                    Merge(source, domain, target.Domains.Single(t => NameEqualityComparer<Domain>.Instance.Equals(domain, t)));
+                }
+            }
+        }
+
+        static void Merge(Protocol protocol, Domain source, Domain target)
+        {
+            Merge(protocol, source, source.Commands, target.Commands);
+            Merge(protocol, source, source.Events, target.Events);
+            Merge(protocol, source, source.Types, target.Types);
+        }
+
+        static void Merge<T>(Protocol protocol, Domain domain, Collection<T> source, Collection<T> target)
+            where T : ProtocolItem
+        {
+            foreach (var item in source)
+            {
+                if (!target.Contains(item, NameEqualityComparer<T>.Instance))
+                {
+                    target.Add(item);
+                }
+                else
+                {
+                    var targetItem = target.Single(t => NameEqualityComparer<T>.Instance.Equals(item, t));
+
+                    if (!targetItem.Equals(item))
+                    {
+                        Console.WriteLine($"{protocol.Alias};{domain.Name};{item.Name};{item};{targetItem};{typeof(T).Name}");
+                    }
+                    else
+                    {
+                        foreach (var v in item.SupportedBy)
+                        {
+                            targetItem.SupportedBy.Add(v);
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/source/ProtocolGenerator/ProtocolProcessor.cs b/source/ProtocolGenerator/ProtocolProcessor.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2286424ad44295645d84ee2932fa53e860bae2e2
--- /dev/null
+++ b/source/ProtocolGenerator/ProtocolProcessor.cs
@@ -0,0 +1,122 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MasterDevs.ChromeDevTools.ProtocolGenerator
+{
+    public class ProtocolProcessor
+    {
+        public static void ResolveTypeReferences(Protocol protocol, Dictionary<string, string> explicitMappings)
+        {
+            foreach (var domain in protocol.Domains)
+            {
+                ResolveTypeReferences(protocol, domain, explicitMappings);
+            }
+        }
+
+        public static void ResolveTypeReferences(Protocol protocol, Domain domain, Dictionary<string, string> explicitMappings)
+        {
+            foreach (var command in domain.Commands)
+            {
+                ResolveTypeReferences(protocol, domain, command, explicitMappings);
+            }
+        }
+
+        public static void ResolveTypeReferences(Protocol protocol, Domain domain, Command command, Dictionary<string, string> explicitMappings)
+        {
+            foreach (var parameter in command.Parameters)
+            {
+                ResolveTypeReferences(protocol, domain, parameter, explicitMappings);
+            }
+
+            foreach (var returnValue in command.Returns)
+            {
+                ResolveTypeReferences(protocol, domain, returnValue, explicitMappings);
+            }
+        }
+
+        public static void ResolveTypeReferences(Protocol protocol, Domain domain, Type property, Dictionary<string, string> explicitMappings)
+        {
+            if (property.TypeReference != null)
+            {
+                // Find the type which is being referenced
+                var referenceParts = property.TypeReference.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
+
+                Domain referencedDomain = null;
+                Type referencedType = null;
+
+                if (referenceParts.Length == 1)
+                {
+                    referencedDomain = domain;
+                    referencedType = domain.GetType(referenceParts[0]);
+                }
+                else if (referenceParts.Length == 2)
+                {
+                    referencedDomain = protocol.GetDomain(referenceParts[0]);
+                    referencedType = referencedDomain.GetType(referenceParts[1]);
+                }
+                else
+                {
+                    throw new ArgumentOutOfRangeException();
+                }
+
+                string fullReferenceName = $"{referencedDomain.Name}.{referencedType.Name}";
+
+                // If it is a string, it can be resolved easily
+                if (referencedType.IsString())
+                {
+                    property.Kind = "string";
+                    property.TypeReference = null;
+                }
+                else if (referencedType.IsInteger())
+                {
+                    property.Kind = "integer";
+                    property.TypeReference = null;
+                }
+                else if (explicitMappings.ContainsKey(fullReferenceName))
+                {
+                    property.TypeReference = explicitMappings[fullReferenceName];
+                }
+            }
+            else if(property.Items != null)
+            {
+                ResolveTypeReferences(protocol, domain, property.Items, explicitMappings);
+            }
+        }
+
+        public static Protocol LoadProtocol(string path, string alias)
+        {
+            string json = File.ReadAllText(path);
+            JsonSerializerSettings settings = new JsonSerializerSettings();
+            settings.MissingMemberHandling = MissingMemberHandling.Error;
+            settings.MetadataPropertyHandling = MetadataPropertyHandling.Ignore;
+            Protocol p = JsonConvert.DeserializeObject<Protocol>(json, settings);
+            p.SourceFile = path;
+            p.Alias = alias;
+
+            foreach (var domain in p.Domains)
+            {
+                foreach (var command in domain.Commands)
+                {
+                    command.SupportedBy.Add(alias);
+                }
+
+                foreach (var @event in domain.Events)
+                {
+                    @event.SupportedBy.Add(alias);
+                }
+
+                foreach (var type in domain.Types)
+                {
+                    type.SupportedBy.Add(alias);
+                }
+            }
+
+            return p;
+        }
+    }
+}
\ No newline at end of file
diff --git a/source/ProtocolGenerator/Type.cs b/source/ProtocolGenerator/Type.cs
index 79c70838ea69b7751fb0a745b6d40946404159a4..7d8f8cfc9850d3fb9b9691e0d5a92b3a14e67bee 100644
--- a/source/ProtocolGenerator/Type.cs
+++ b/source/ProtocolGenerator/Type.cs
@@ -1,14 +1,17 @@
 using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
 using System.Collections.ObjectModel;
+using System.Linq;
 
 namespace MasterDevs.ChromeDevTools.ProtocolGenerator
 {
-    class Type : ProtocolItem
+    public class Type : ProtocolItem
     {
         public Type()
         {
-            this.Enum = new Collection<string>();
-            this.Properties = new Collection<Property>();
+            this.Enum = new HashSet<string>();
+            this.Properties = new HashSet<Property>();
         }
 
         [JsonProperty(PropertyName = "Id")]
@@ -18,20 +21,20 @@ namespace MasterDevs.ChromeDevTools.ProtocolGenerator
             set;
         }
 
-        [JsonProperty(PropertyName ="type")]
+        [JsonProperty(PropertyName = "type")]
         public string Kind
         {
             get;
             set;
         }
 
-        public Collection<string> Enum
+        public HashSet<string> Enum
         {
             get;
             set;
         }
 
-        public Collection<Property> Properties
+        public HashSet<Property> Properties
         {
             get;
             set;
@@ -61,5 +64,109 @@ namespace MasterDevs.ChromeDevTools.ProtocolGenerator
             get;
             set;
         }
+
+        public string TypeName
+        {
+            get
+            {
+                if (this.TypeReference != null)
+                {
+                    return this.TypeReference;
+                }
+                else if (this.Items != null)
+                {
+                    return this.Items.TypeName + "[]";
+                }
+                else if (this.Kind != null && this.Kind != "object")
+                {
+                    return this.Kind;
+                }
+                else
+                {
+                    return this.Name;
+                }
+            }
+        }
+        public override bool Equals(object obj)
+        {
+            var other = obj as Type;
+
+            if (other == null)
+            {
+                return false;
+            }
+
+            bool equals = base.Equals(obj);
+            equals &= string.Equals(this.Kind, other.Kind, StringComparison.OrdinalIgnoreCase);
+            equals &= this.Enum.SetEquals(other.Enum);
+            equals &= this.Properties.SetEquals(other.Properties);
+            equals &= Type.Equals(this.Items, other.Items);
+            equals &= this.MinItems == other.MinItems;
+            equals &= this.MaxItems == other.MaxItems;
+            equals &= string.Equals(this.TypeReference, other.TypeReference, StringComparison.OrdinalIgnoreCase);
+
+            return equals;
+        }
+
+        public override int GetHashCode()
+        {
+            unchecked
+            {
+                int hash = base.GetHashCode();
+
+                if (this.Kind != null)
+                {
+                    hash = hash * 23 + StringComparer.OrdinalIgnoreCase.GetHashCode(this.Kind);
+                }
+
+                hash = hash * 23 + this.Enum.GetCollectionHashCode();
+                hash = hash * 23 + this.Properties.GetCollectionHashCode();
+
+                if (this.Items != null)
+                {
+                    hash = hash * 23 + this.Items.GetHashCode();
+                }
+
+                hash = hash * 23 + this.MinItems.GetHashCode();
+                hash = hash * 23 + this.MaxItems.GetHashCode();
+
+                if (this.TypeReference != null)
+                {
+                    hash = hash * 23 + StringComparer.OrdinalIgnoreCase.GetHashCode(this.TypeReference);
+                }
+
+                return hash;
+            }
+        }
+
+        public bool IsString()
+        {
+            return string.Equals(this.Kind, "string", StringComparison.OrdinalIgnoreCase);
+        }
+
+        public bool IsInteger()
+        {
+            return string.Equals(this.Kind, "integer", StringComparison.OrdinalIgnoreCase);
+        }
+
+        public bool IsEnum()
+        {
+            return this.Enum.Any();
+        }
+
+        public bool IsClass()
+        {
+            return this.Properties.Any();
+        }
+
+        public bool IsObject()
+        {
+            return string.Equals(this.Kind, "object", StringComparison.OrdinalIgnoreCase);
+        }
+
+        public override string ToString()
+        {
+            return this.TypeName;
+        }
     }
 }
diff --git a/source/ProtocolGenerator/Version.cs b/source/ProtocolGenerator/Version.cs
index b9d6dc8cb2b39cf3fbdee36cfbd12ca6a3664935..64853209e0e1d9b9dd84215952baea09db845ccb 100644
--- a/source/ProtocolGenerator/Version.cs
+++ b/source/ProtocolGenerator/Version.cs
@@ -1,6 +1,6 @@
 namespace MasterDevs.ChromeDevTools.ProtocolGenerator
 {
-    class Version
+    public class Version
     {
         public string Major
         {