you could make a runtime code-generator like this:
public static string GenerateClass(string className, ExpandoObject eObj)
{
    var sb = new StringBuilder();
    sb.Append("public class ");
    sb.Append(className);
    sb.AppendLine();
    sb.Append("{");
    sb.AppendLine();
    foreach (var property in (IDictionary<String, Object>)eObj)
    {
        sb.Append("    ");
        sb.Append(property.Value.GetType());
        sb.Append(" ");
        sb.Append(property.Key);
        sb.Append(" ");
        sb.Append("{ get; set; }");
        sb.AppendLine();
    }
    sb.Append("}");
    sb.AppendLine();
    return sb.ToString();
}
passing your expando object returns:
public class test
{
    System.String property1 { get; set; }
    System.Int32 property2 { get; set; }
}
usage:
static void Main(string[] args)
{
    dynamic test = new System.Dynamic.ExpandoObject();
    test.property1 = "test";
    test.property2 = 123;
    Console.WriteLine(GenerateClass("test", (ExpandoObject)test));
}
**edit: for nested types, you can do this: **
public static string GenerateClass(string className, ExpandoObject eObj)
{
    var sb = new StringBuilder();
    sb.Append("public class ");
    sb.Append(className);
    sb.AppendLine();
    sb.Append("{");
    sb.AppendLine();
    foreach (var property in (IDictionary<String, Object>)eObj)
    {
        string typeName = property.Value.GetType().Name;
        if (property.Value is ExpandoObject nestedEObj)
        {
            typeName = property.Key;
            sb.AppendLine();
            foreach (string nestedClassLine in GenerateClass(property.Key, nestedEObj).Split(Environment.NewLine))
            {
                sb.Append("    ");
                sb.Append(nestedClassLine);
                sb.AppendLine();
            }
        }
        sb.Append("    ");
        sb.Append(typeName);
        sb.Append(" ");
        sb.Append(property.Key);
        sb.Append(" ");
        sb.Append("{ get; set; }");
        sb.AppendLine();
    }
    sb.Append("}");
    sb.AppendLine();
    return sb.ToString();
}
usage:
    static void Main(string[] args)
    {
        dynamic test = new System.Dynamic.ExpandoObject();
        test.property1 = "test";
        test.property2 = 123;
        dynamic nest = new System.Dynamic.ExpandoObject();
        nest.property1 = "testForNest";
        nest.property2 = 456;
        test.nest = nest;
        Console.WriteLine(GenerateClass("test", (ExpandoObject)test));
    }
produces:
public class test
{
    String property1 { get; set; }
    Int32 property2 { get; set; }
    public class nest
    {
        String property1 { get; set; }
        Int32 property2 { get; set; }
    }
    nest nest { get; set; }
}