diff --git a/dotnet/src/Microsoft.AutoGen/Core/PythonEquiv/TypeSubscription.cs b/dotnet/src/Microsoft.AutoGen/Core/PythonEquiv/TypeSubscription.cs
new file mode 100644
index 000000000..84a8f83f4
--- /dev/null
+++ b/dotnet/src/Microsoft.AutoGen/Core/PythonEquiv/TypeSubscription.cs
@@ -0,0 +1,101 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// TypeSubscription.cs
+
+using System.Diagnostics.CodeAnalysis;
+
+namespace Microsoft.AutoGen.Contracts.Python;
+
+///
+/// This subscription matches on topics based on the exact type and maps to agents using the source of the topic as the agent key.
+/// This subscription causes each source to have its own agent instance.
+///
+///
+/// Example:
+///
+/// var subscription = new TypeSubscription("t1", "a1");
+///
+/// In this case:
+/// - A with type `"t1"` and source `"s1"` will be handled by an agent of type `"a1"` with key `"s1"`.
+/// - A with type `"t1"` and source `"s2"` will be handled by an agent of type `"a1"` with key `"s2"`.
+///
+public class TypeSubscription : ISubscriptionDefinition
+{
+ private readonly string _topicType;
+ private readonly AgentType _agentType;
+ private readonly string _id;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The exact topic type to match against.
+ /// Agent type to handle this subscription.
+ /// Unique identifier for the subscription. If not provided, a new UUID will be generated.
+ public TypeSubscription(string topicType, AgentType agentType, string? id = null)
+ {
+ _topicType = topicType;
+ _agentType = agentType;
+ _id = id ?? Guid.NewGuid().ToString();
+ }
+
+ ///
+ /// Gets the unique identifier of the subscription.
+ ///
+ public string Id => _id;
+
+ ///
+ /// Gets the exact topic type used for matching.
+ ///
+ public string TopicType => _topicType;
+
+ ///
+ /// Gets the agent type that handles this subscription.
+ ///
+ public AgentType AgentType => _agentType;
+
+ ///
+ /// Checks if a given matches the subscription based on an exact type match.
+ ///
+ /// The topic to check.
+ /// true if the topic's type matches exactly, false otherwise.
+ public bool Matches(TopicId topic)
+ {
+ return topic.Type == _topicType;
+ }
+
+ ///
+ /// Maps a to an . Should only be called if returns true.
+ ///
+ /// The topic to map.
+ /// An representing the agent that should handle the topic.
+ /// Thrown if the topic does not match the subscription.
+ public AgentId MapToAgent(TopicId topic)
+ {
+ if (!Matches(topic))
+ {
+ throw new InvalidOperationException("TopicId does not match the subscription.");
+ }
+
+ return new AgentId(_agentType, topic.Source);
+ }
+
+ ///
+ /// Determines whether the specified object is equal to the current subscription.
+ ///
+ /// The object to compare with the current instance.
+ /// true if the specified object is equal to this instance; otherwise, false.
+ public override bool Equals([NotNullWhen(true)] object? obj)
+ {
+ return obj is TypeSubscription other &&
+ (Id == other.Id ||
+ (AgentType == other.AgentType && TopicType == other.TopicType));
+ }
+
+ ///
+ /// Returns a hash code for this instance.
+ ///
+ /// A hash code for this instance, suitable for use in hashing algorithms and data structures.
+ public override int GetHashCode()
+ {
+ return HashCode.Combine(Id, AgentType, TopicType);
+ }
+}