diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
index 50196b84f04..bec39e9f50b 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
@@ -218,6 +218,52 @@ INamedTypeSymbol symbol
                 source.Append("    }\n");
             }
 
+            // Generate the SignalEmit class
+            source.AppendLine($"    public new class SignalEmit : {symbol.BaseType.FullQualifiedName()}.SignalEmit")
+                    .AppendLine("    {");
+
+            source.AppendLine($"        public SignalEmit({GodotClasses.Object} bound) : base(bound) {{ }}");
+
+            foreach (var signalDelegate in godotSignalDelegates)
+            {
+                string signalName = signalDelegate.Name;
+                var parameters = signalDelegate.InvokeMethodData.Method.Parameters;
+                string @params = "";
+                string paramsCall = "";
+
+                if (parameters.Length > 0)
+                {
+                    paramsCall += ", ";
+
+                    for (int i = 0; i < parameters.Length; i++)
+                    {
+                        @params += parameters[i].ToString()
+                                + " "
+                                + parameters[i].Name.ToString();
+
+                        paramsCall += parameters[i].Name.ToString();
+
+                        if (i != parameters.Length - 1)
+                        {
+                            @params += ", ";
+                            paramsCall += ", ";
+                        }
+                    }
+                }
+
+                source.AppendLine($"        /// <inheritdoc cref=\"{signalDelegate.DelegateSymbol.FullQualifiedName()}\"/>");
+
+                source.Append($"        public void {signalName}({@params})")
+                        .AppendLine($" => bound.EmitSignal({symbol.NameWithTypeParameters()}.SignalName.{signalName}{paramsCall});");
+            }
+
+            source.AppendLine("    }");
+
+            // Generate the Emit property
+            source.AppendLine("    private SignalEmit _emit;")
+                .AppendLine("    /// <summary>A helper to quickly and safely emit signals.</summary>")
+                .AppendLine("    public new SignalEmit Emit => _emit ??= new(this);");
+
             source.Append("#pragma warning restore CS0109\n");
 
             // Generate signal event
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index b90321b5869..e50d7f425c4 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -1541,6 +1541,11 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
 		output.append(itype.name);
 		output.append("\";\n");
 
+		// Add Emit property
+		output << MEMBER_BEGIN "private SignalEmit _emit;\n"
+			   << MEMBER_BEGIN "/// <summary>A helper to quickly and safely emit signals.</summary>\n"
+			   << MEMBER_BEGIN "public new SignalEmit Emit => _emit \?\?= new(this);\n";
+
 		if (itype.is_instantiable) {
 			// Add native constructor static field
 
@@ -1762,6 +1767,59 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
 	}
 	output << INDENT1 "}\n";
 
+	//SignalEmit
+	if (!itype.is_singleton) {
+		if (is_inherit) {
+			output << MEMBER_BEGIN "public new class SignalEmit : " << obj_types[itype.base_name].proxy_name << ".SignalEmit\n"
+				   << INDENT1 "{\n";
+			// Generate ctor
+			output << INDENT2 "public SignalEmit(Godot.Object bound) : base(bound) { }\n";
+		} else {
+			output << MEMBER_BEGIN "public class SignalEmit\n"
+				   << INDENT1 "{\n";
+			// Generate bound field and ctor
+			output << INDENT2 "protected Godot.Object bound;\n"
+				   << INDENT2 "public SignalEmit(Godot.Object bound)\n"
+				   << INDENT2 "{\n"
+				   << INDENT3 "this.bound = bound;\n"
+				   << INDENT2 "}\n";
+		}
+		// Generate SignalEmit's methods
+		for (const SignalInterface &isignal : itype.signals_) {
+			String arg_sig;
+			String arg_call_sig;
+
+			// Get arguments
+			const ArgumentInterface &first_arg = isignal.arguments.front()->get();
+			for (const ArgumentInterface &iarg : isignal.arguments) {
+				const TypeInterface *arg_type = _get_type_or_null(iarg.type);
+
+				// No need to Add ERR_FAIL_COND's because there already in _generate_cs_signal
+
+				if (&iarg != &first_arg) {
+					arg_sig += ", ";
+				}
+				arg_call_sig += ", ";
+
+				arg_sig += arg_type->cs_type;
+				arg_sig += " ";
+				arg_sig += iarg.name;
+				arg_call_sig += iarg.name;
+			}
+
+			output << MEMBER_BEGIN INDENT1 "/// <summary>\n"
+				   << INDENT2 "/// "
+				   << "Raises the"
+				   << "<see cref=\"" BINDINGS_NAMESPACE "." + itype.proxy_name + "." + isignal.proxy_name + "\"/>"
+				   << " signal.\n"
+				   << INDENT2 "/// </summary>\n";
+
+			output << INDENT2 "public void " << isignal.proxy_name << "(" << arg_sig << ")"
+				   << " => bound.EmitSignal(\"" << isignal.name << "\"" << arg_call_sig << ");\n";
+		}
+		output << INDENT1 "}\n";
+	}
+
 	output.append(CLOSE_BLOCK /* class */);
 
 	output.append("\n"