title: polymorphic Json deserialization in nested scenario
body: <p>I have some classes that I want to (de-)serialize:</p>
  <pre><code>public class Top
  {
      public Top(Sub content) { Content = content; }
  
      public Sub Content { get; init; }
  }
  
  public class Sub
  {
      public Sub(Sub? entry) { Entry = entry; Type = SubType.super; }
  
      public Sub? Entry { get; init; }
      public SubType Type { get; init; }
  }
  
  public class SubA : Sub
  {
      public SubA(Sub? entry) : base(entry) { Type = SubType.a; }
  }
  
  public enum SubType { super, a }
  </code></pre>
  <p>Example object:</p>
  <pre><code>var top = new Top(new SubA(new Sub(new SubA(null))));
  </code></pre>
  <p>To serialize, I just need to use <code>JsonSerializer.Serialize</code> with some options to get what I want:</p>
  <pre><code>var json = JsonSerializer.Serialize(top, new JsonSerializerOptions
      { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
        Converters = { _enumConverter } });
  // result:
  // {&quot;Content&quot;:{&quot;Entry&quot;:{&quot;Entry&quot;:{&quot;Type&quot;:&quot;a&quot;},&quot;Type&quot;:&quot;super&quot;},&quot;Type&quot;:&quot;a&quot;}}
  </code></pre>
  <p>Deserializing does not work out of the box - it always deserializes to <code>Sub</code>, never to <code>SubA</code>. So I tried writing my own <code>JsonConverter</code> that finds the type <code>T</code> to deserialize to (from the JSON <code>Type</code> property), then calls the appropriate <code>JsonSerializer.Deserialize&lt;T&gt;</code> method. But I end up either in a StackOverflow or in losing my converter after one level:</p>
  <pre><code>public class SubConverter : JsonConverter&lt;Sub&gt;
  {    
      public override BaseType Read(ref Utf8JsonReader reader, Type typeToConvert,
          JsonSerializerOptions options)
      {
          // Create a copy of the reader to find type. Necessary because after type was found, we
          // need to deserialize from the start, but resetting to start position is not possible.
          var typeReader = reader;
  
          bool discriminatorFound = false;
          while (typeReader.Read())
          {
              if (typeReader.TokenType == JsonTokenType.StartObject
                  || typeReader.TokenType == JsonTokenType.StartArray)
              {
                  typeReader.Skip();
                  continue;
              }
              if (typeReader.TokenType != JsonTokenType.PropertyName)
                  continue;
              if (typeReader.GetString() != TypeDiscriminatorPropertyName)
                  continue;
              discriminatorFound = true;
              break;
          }
  
          if (!discriminatorFound)
              throw new JsonException(
                  $&quot;type discriminator property \&quot;{TypeDiscriminatorPropertyName}\&quot; was not found&quot;);
  
          if (!typeReader.Read() || typeReader.TokenType != JsonTokenType.String)
              throw new JsonException(&quot;type discriminator value does not exist or is not a string&quot;);
  
          var typeString = typeReader.GetString();
          var deserializationType = typeString == SubType.super.ToString() ? typeof(Sub) : typeof(SubA);
  
          // !!!
          // if THIS, is not removed, will get infinite loop (-&gt; StackOverflowException)
          // if THIS is removed, will not get polymorphic deserialization in properties below
          var options2 = new JsonSerializerOptions(options);
          if (options2.Converters.Contains(this))
              options2.Converters.Remove(this);
          BaseType inst = (BaseType)JsonSerializer.Deserialize(ref reader, deserializationType, options2)!;
  
          return inst;
      }
  
      // not needed; we only use this converter for deserialization
      public override void Write(Utf8JsonWriter writer, BaseType value, JsonSerializerOptions options)
      { throw new NotImplementedException(); }
  }
  </code></pre>
  <p>If I just pass the <code>options</code> unchanged into <code>JsonSerializer.Deserialize</code>, I will get an inifinite loop (<code>JsonSerializer.Deserialize</code> will call <code>SubConverter.Read</code> and vice versa).</p>
  <p>If I remove the <code>SubConverter</code> from the options as in the code above, I lose it for all content in the levels below. So instead of the original object <code>foo</code> that was like this:</p>
  <pre><code>Top -&gt; SubA -&gt; Sub -&gt; SubA
  </code></pre>
  <p>I now get</p>
  <pre><code>Top -&gt; SubA -&gt; Sub -&gt; Sub
                  ^      ^
                  │      └─ because `SubConverter` was removed, cannot deserialize as SubA
                  └─ here we removed `SubConverter`
  </code></pre>
  <p><strong>What do I do now?</strong></p>
  <p>I do not want to write the whole deserialization on my own, only the necessary bit(s). (My real use case is much more complex than the classes in this question.)</p>