Repository/persistence-service implementation
I would tend to agree with Adrian's comment that you might be better off finding some lightweight / micro ORM to start from, if bigger things such as EF or NHibernate aren't options for you.

Still, if you really want to go all the way long your own route with generics, then, FWIW, I'd probably put it along the lines of something like:

(just a rough, compilable sketch; untested, clearly not thread-safe, with no provisions or hints on how to go from the DataTables to your DB engine's SQL, etc)

public interface IStore&lt;TItem&gt;
{
    TPersistent Deserialize&lt;TPersistent&gt;(TItem item)
        where TPersistent : class, new();

    TItem Serialize&lt;TPersistent&gt;(TPersistent instance)
        //if only for consistency with Deserialize:
        where TPersistent : class, new();
}

public interface IPersistence&lt;TStore, TItem&gt;
    where TStore : IStore&lt;TItem&gt;
{
    void Add&lt;TPersistent&gt;(TPersistent instance)
        //if only for consistency with GetById, or other various
        //Getters/Finders/Selectors:
        where TPersistent : class, new();

    TPersistent GetById&lt;TPersistent&gt;(long id)
        where TPersistent : class, new();
}

public abstract class Persistence&lt;TStore, TItem&gt; : IPersistence&lt;TStore, TItem&gt;
    where TStore : IStore&lt;TItem&gt;
{
    protected abstract TItem Get&lt;TPersistent&gt;(long id);

    protected abstract void Insert(TItem item);

    // Useful to use TStore here (and not just IStore&lt;TItem&gt;) to allow for
    // type-safe internal friendship between the store and persistence implementations later on,
    // if needed
    protected TStore Store { get; private set; }

    protected Persistence(IStore&lt;TItem&gt; store)
    {
        // Note we *want* this to barf at construction time,
        // if it turns out that store (the parameter)
        // does not conform to TStore
        Store = (TStore)store;
    }

    void IPersistence&lt;TStore, TItem&gt;.Add&lt;TPersistent&gt;(TPersistent instance)
    {
        Insert(Store.Serialize(instance));
    }

    TPersistent IPersistence&lt;TStore, TItem&gt;.GetById&lt;TPersistent&gt;(long id)
    {
        return Store.Deserialize&lt;TPersistent&gt;(Get&lt;TPersistent&gt;(id));
    }
}

/// &lt;summary&gt;
/// Friend of DataTablePersistence (via its internal DataSet)
/// &lt;/summary&gt;
public class DataTableStore : IStore&lt;DataRow&gt;
{
    internal readonly DataSet DataSet;

    internal DataTable EnsureTable(Type instanceType)
    {
        var tableName = instanceType.Name;
        DataTable table;
        if (!DataSet.Tables.Contains(tableName))
        {
            table = new DataTable(tableName);
            //(left to-do) also define the table schema (columns),
            //after what instanceType tells us
            DataSet.Tables.Add(tableName);
        }
        else
        {
            table = DataSet.Tables[tableName];
        }
        return table;
    }

    public DataTableStore()
    {
        DataSet = new DataSet();
    }

    TPersistent IStore&lt;DataRow&gt;.Deserialize&lt;TPersistent&gt;(DataRow item)
    {
        var instance = new TPersistent();
        //e.g., use System.Reflection to hydrate instance (from item)
        return instance;
    }

    DataRow IStore&lt;DataRow&gt;.Serialize&lt;TPersistent&gt;(TPersistent instance)
    {
        var table = EnsureTable(instance.GetType());
        var item = table.NewRow();
        //e.g., use System.Reflection to dehydrate instance (into item)
        return item;
    }
}

/// &lt;summary&gt;
/// Friend of DataTableStore (via DataTableStore's internal DataSet)
/// &lt;/summary&gt;
public class DataTablePersistence : Persistence&lt;DataTableStore, DataRow&gt;
{
    protected override DataRow Get&lt;TPersistent&gt;(long id)
    {
        var table = Store.EnsureTable(typeof(TPersistent));
        return table.Rows.Find(id);
    }

    protected override void Insert(DataRow item)
    {
        // presumably, item was created by some DataSet[&lt;table name&gt;].NewRow(),
        // so, it already knows the table in which it ought to be inserted
        item.Table.Rows.Add(item);
    }

    public DataTablePersistence()
        : base(new DataTableStore())
    {
    }
}

public class Program
{
    public class Person
    {
        public long Id { get; set; }

        public string First { get; set; }

        public string Last { get; set; }
    }

    public class Asset
    {
        public long Id { get; set; }

        public string Category { get; set; }

        public string Name { get; set; }
    }

    public static void Main(string[] args)
    {
        IPersistence&lt;DataTableStore, DataRow&gt; persistence = new DataTablePersistence();

        persistence.Add(new Person { First = "John", Last = "Smith" });

        persistence.Add(new Asset { Category = "Vehicle", Name = "Cadillac" });

        var john = persistence.GetById&lt;Person&gt;(1);

        var asset = persistence.GetById&lt;Asset&gt;(1);

        //etc, etc
    }
}


Finally, it'll get more interesting (challenging) if you want to support dehydrating (i.e., emitting SQL insert/update/delete) arbitrary object graphs where some instances are transient/freshly created, while others come with their existing keys from your underlying DB, etc)

'Hope this helps.